feat(files): serve a fileset straight from a GitHub repository [ASTD-519] - #1663
Draft
marcusds wants to merge 3 commits into
Draft
feat(files): serve a fileset straight from a GitHub repository [ASTD-519]#1663marcusds wants to merge 3 commits into
marcusds wants to merge 3 commits into
Conversation
Importing an agent from GitHub needs the repository's files in a spec fileset, and private repositories need a token to read them. Deployment staging already downloads the spec fileset through the files API, so a fileset backed by GitHub serves a deployment with no copy step and the token never leaves the cluster. GithubStorageConfig names the repository, an optional directory within it, and the secret holding a personal access token; the files service resolves that secret and hands the backend its value, the same path the Huggingface and NGC backends already take. resolve_config pins the requested branch or tag to a commit SHA when the fileset is created, so a push to the branch cannot shift the files under a running deployment, and the cache key is scoped to that SHA. A 404 is reported as a config error rather than an access error: without a token that can see it, a private repository and a missing one are the same response. A 403 carrying an exhausted rate limit is reported as unavailable, since it is transient and retrying is the fix. Uploads and deletes are refused and owns_storage_data stays false, so deleting a fileset never reaches back into the repository. Signed-off-by: mschwab <mschwab@nvidia.com>
Contributor
Contributor
|
Signed-off-by: mschwab <mschwab@nvidia.com>
The upload modal now takes a repository URL and an optional workspace secret alongside the directory picker. The spec fileset is created with a GitHub storage config rather than by uploading files, so the token stays in the files service and the browser never holds it. agent.yaml is read back through the files API once the fileset exists, which is also the only way to see a private repository's contents from here. A failure at that point rolls the fileset back, matching the upload path. The agent name has to be settled before the fileset can be named, so it is prefilled from the repository or the chosen subdirectory instead of being read out of agent.yaml the way the upload path does. claimFileset and the rollback move to agentSpecFileset.ts so both create paths share one implementation of who owns a spec fileset. Widening the storage union reaches the datasets table, which keeps its own copy of it, and the storage-backend label map. Signed-off-by: mschwab <mschwab@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Studio can create a Fabric agent from a GitHub repository URL, including a private one. The agent's spec fileset is backed directly by the repository and read with a personal access token held in the Secrets service — the token never reaches the browser.
Deployment staging already downloads the agent spec fileset through the files API (
stage_fabric_spec_dir→sdk.download(fileset=...)), so a GitHub-backed fileset serves a deployment with no copy step and the token never leaves the cluster.Related Issue
ASTD-519
Changes
GithubStorageConfig— owner, repo, revision (+original_revision), an optional directory within the repo,token_secret, andapi_base_urlfor GitHub Enterprise. Declares its token viaget_secret_references(), the same mechanism the Huggingface and NGC configs use.GithubStorageImpl—list_filesfrom the recursive trees API,downloadstreaming the contents API withAccept: application/vnd.github.raw(which serves private repos),resolve_configpinning a branch or tag to a commit SHA, and a cache key scoped to that SHA.storage_impl_factorydispatches the new config type.https://api.github.comadded to the files serviceallowed_external_hostsdefault; config reference doc regenerated.claimFileset/rollback move toagentSpecFileset.tsso both create paths share one implementation.Notes on behaviour worth reviewing:
resolve_configpins the revision at fileset creation. A push to the branch cannot shift the files under a running deployment.original_revisionkeeps what the user asked for.GithubConfigError, not an access error. Without a token that can see it, a private repository and a nonexistent one produce the same response, so the message says "has no X, or the token cannot see it" rather than asserting which.x-ratelimit-remaining: 0maps toGithubUnavailableError. It is transient; calling it a permissions problem sends people after the wrong fix.upload/deleteare refused andowns_storage_datastays false, so deleting a fileset never reaches back into the repository.Type of Change
Quality Gates
docs/set-up/config-reference.mdxis regenerated by the pre-commit hook. The new UI is self-describing; no docs page covers the upload modal today.Verification
Signed-off-by:traileruv run pre-commit run -apasses, or any blocked checks are identified belowTargeted validation:
uv run pytest services/core/files/tests— 610 passed, 51 skipped. The newtest_github_backend.pycontributes 33.src/routes/agents/AgentsListRoute/UploadAgentModal+src/api/agents— 83 passed.src/components/DatasetsTable+src/util(the widened-union call sites) — 467 passed.typecheckandlint— clean.uv run ruff check/uv run ruff format --checkon the changed files — clean.uv run --frozen ty checkonbackends/github.pyandfiles/storage_config.py— clean.uv run pre-commit run -awas not run.--no-verify:helm-docsis not installed locally, and theuv-lockhook requires uv 0.9.14 against a local uv 0.9.30. This change touches no Helm chart and nopyproject.toml, so neither applies; CI runs both.Notes for review
agent.yaml. The fileset is named after the agent, so the name has to be settled before the fileset exists — andagent.yamlonly becomes readable once it does. The upload path still reads the name out of the file. The user can edit the prefilled value either way./tree/URL — the first segment aftertreeis taken as the ref.@<ref>is the explicit form, matching the Experimentalist plugin's<git-url>[@<ref>][#<agent_path>]spec.Not in this PR
make update-sdk(Stainless / Python SDK). The web SDK is generated locally by orval fromopenapi.yamland is gitignored; the Python SDK will drift until that is run separately.