fullsend inference
Manage the inference credentials agent runs use. provision, deprovision and status create, inspect, and remove the GCP Workload Identity Federation (WIF) pool, OIDC provider, and IAM bindings that let GitHub Actions workflows authenticate with GCP for Agent Platform (Vertex) access. openai enrols repositories with OpenAI WIF for GPT models on the pi runtime. gateway status is not part of WIF: it checks a repository's inference.gateway block and whether the gateway accepts the job's OIDC assertion through direct OIDC trust (no token exchange).
Commands
| Command | Description | Who runs it / permission |
|---|---|---|
fullsend inference provision <org|owner/repo> | Create WIF pool/provider and grant Agent Platform access | GCP project admin, with roles/iam.workloadIdentityPoolAdmin and roles/resourcemanager.projectIamAdmin |
fullsend inference deprovision <org|owner/repo> | Remove org or repo from WIF | GCP project admin, with roles/iam.workloadIdentityPoolAdmin |
fullsend inference status <org|owner/repo> | Check WIF health and print config values | Read access on the GCP project: roles/iam.workloadIdentityPoolViewer and roles/browser |
fullsend inference openai request <owner/repo>[,…] | Generate WIF provider/mapping request for OpenAI admin | Anyone; needs no credentials |
fullsend inference openai import [reply.json] | Import OpenAI WIF identifiers into config | Repo admin. Writes .fullsend/config.yaml locally, to commit afterwards; --variables needs a GitHub token that can set repository variables |
fullsend inference openai status <owner/repo> | Check OpenAI WIF configuration and exchange status | Config checks: anyone, from a checkout of the repository. Live exchange: only inside a GitHub Actions job in <owner/repo> with id-token: write, so a repo writer adds the workflow |
fullsend inference gateway status <owner/repo> | Check inference gateway configuration and authentication | Config checks: anyone, from a checkout of the repository. Live check, oidc mode only: inside a GitHub Actions job in <owner/repo> with id-token: write, so a repo writer adds the workflow |
inference provision
Creates a WIF pool (fullsend-inference), an OIDC provider (github-oidc), and grants roles/aiplatform.user to the WIF principal. Idempotent and safe to re-run.
fullsend inference provision <org> \
--project "<GCP_PROJECT>"Per-repo mode scopes the WIF provider to a single repository:
fullsend inference provision <owner/repo> \
--project "<GCP_PROJECT>"Flags
| Flag | Default | Description |
|---|---|---|
--project | GCP project ID | |
--region | global | GCP region |
Required IAM roles
| Role | Description |
|---|---|
roles/iam.workloadIdentityPoolAdmin | Create WIF pool and provider |
roles/resourcemanager.projectIamAdmin | Grant roles/aiplatform.user to WIF principals |
Required GCP APIs
gcloud services enable \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
aiplatform.googleapis.com \
--project="$GCP_PROJECT"inference deprovision
Removes an org or repo from WIF by deleting the IAM binding and (optionally) the WIF provider.
fullsend inference deprovision <org|owner/repo> \
--project "<GCP_PROJECT>"Required IAM roles
| Role | Description |
|---|---|
roles/iam.workloadIdentityPoolAdmin | Modify WIF pool and provider |
inference status
Checks WIF health and prints the configuration values needed for github setup.
fullsend inference status <org|owner/repo> \
--project "<GCP_PROJECT>"Read-only — makes no changes.
inference openai
Commands for enrolling repositories with OpenAI Workload Identity Federation (see the operator guide). They need neither GCP access nor an OpenAI key.
What reaches the network, and what does not:
| Command | Network |
|---|---|
request | None. The document is computed from the repository names. |
import | None, unless --variables is passed: that calls the GitHub API through the forge client to set the three repository variables. |
status | Reads configuration only, except inside a GitHub Actions job with id-token: write, where it performs one token exchange with OpenAI to prove the mapping accepts that job's repository — reporting the granted scope and expiry, never the token. |
No OpenAI API key is used or created by any of them.
inference openai request
Generates the request document an administrator needs to enable OpenAI WIF for one or more repositories. Every value is computed from the repository names. Nothing is sent anywhere; the command needs no credentials.
fullsend inference openai request <owner/repo>[,<owner/repo>…] \
[--audience "<audience>"] \
[--project "<openai-project>"] \
[--service-account "<existing-sa-id>"] \
[--ref "refs/heads/<branch>"] \
[--format json|md] \
[--out <file>]| Flag | Default | Description |
|---|---|---|
--audience | fullsend://<owner> | OpenAI Workload Identity audience |
--project | (empty) | OpenAI project name or ID for the service accounts |
--service-account | (none) | Map this existing service account instead of asking for fullsend-<repo>-ci to be created in the mapping |
--ref | (none) | Optional tightening. Must be a full ref (refs/…). When set, emits two mappings per repository — one asserting the given ref (e.g. refs/heads/main) and one asserting refs/pull/* — so both branch and PR-review-triggered runs work. Without --ref, mappings assert iss, aud, and repository only (no ref), matching the Vertex path's repository-scoped trust. The two-mapping cost halves the 50-mapping-per-provider budget to 25 repositories |
--format | json | Output format: json (versioned schema) or md (copy-paste ticket) |
--out | (stdout) | Write output to a file |
inference openai import
Takes the administrator's reply and writes inference.openai into .fullsend/config.yaml through the same setters as fullsend github setup --openai-*. All three identifiers must be present — a partial trio is refused, and the config is validated before it is written. The write is local: commit .fullsend/config.yaml afterwards, since fullsend reads the base branch for pull-request events.
The reply file may be either the bare reply object or the whole document request --format json produced with its reply section filled in — an administrator can edit and return the same file. When it names service accounts for several repositories, pass --repo <owner/repo> to choose one, or --service-account-id to give the value outright.
# From a reply JSON file:
fullsend inference openai import reply.json
# From flags:
fullsend inference openai import \
--audience "fullsend://<owner>" \
--identity-provider-id "<idp-id>" \
--service-account-id "<sa-id>"
# Set repository variables instead of config.yaml:
fullsend inference openai import \
--variables --repo <owner/repo> \
--audience "fullsend://<owner>" \
--identity-provider-id "<idp-id>" \
--service-account-id "<sa-id>"| Flag | Default | Description |
|---|---|---|
--audience | OpenAI Workload Identity audience | |
--identity-provider-id | OpenAI identity provider ID | |
--service-account-id | OpenAI service account ID | |
--fullsend-dir | .fullsend | Path to the .fullsend configuration directory |
--variables | false | Set FULLSEND_OPENAI_* repository variables instead of config.yaml |
--repo | Two roles: the target repository for --variables, and the repository to select from a reply that names several (service_account_ids). Matched case-insensitively |
inference openai status
Prints the resolved OpenAI WIF identifiers and their source (config layer or environment variables), and flags a partial trio. When nothing is configured, reports that a run will refuse the openai provider and names both remedies: the WIF trio, or the FULLSEND_OPENAI_API_KEY repository secret (exported as OPENAI_API_KEY). A static OPENAI_API_KEY already in the environment is reported as the source; in CI the runner warns and WIF remains preferred. When run inside a GitHub Actions job with id-token: write, performs one exchange and reports the returned scope and expiry without ever printing the token.
fullsend inference openai status <owner/repo> \
[--fullsend-dir ".fullsend"]| Flag | Default | Description |
|---|---|---|
--fullsend-dir | .fullsend | Path to the .fullsend configuration directory |
inference gateway status
Prints the resolved inference.gateway block (ADR 0137) — url, audience, the auth mode and the model list (models or models_file) — with the config layer each comes from (config.yaml or config.base.yaml), and flags a partial block (url missing, or audience missing in the oidc mode). The block has no environment-variable override. For a complete block it also reports the Claude Code route: the ANTHROPIC_BASE_URL a claude runtime gateway/<model> run gets, and how the credential reaches it (an apiKeyHelper in the oidc mode, an ANTHROPIC_AUTH_TOKEN placeholder in the api-key mode, sent as Authorization: Bearer in both, and in the oidc mode Claude Code also copies the helper value into x-api-key; see Claude Code § Inference gateway route). In the api-key mode (ADR 0138) it warns that the mode relies on a long-lived secret and recommends oidc when the gateway supports it, reports whether FULLSEND_INFERENCE_GATEWAY_API_KEY is set (never its value), and stops at the config checks. In the oidc mode, when run inside a GitHub Actions job in <owner/repo> with id-token: write, fetches one GitHub OIDC assertion for the configured audience, reports its expiry (exp, lifetime, time left), and sends one authenticated request, GET <url>/v1/models with the assertion as a bearer token (under the url's path prefix when it has one, for example GET https://gateway.example.com/team-a/v1/models). It reports the HTTP status and reads the reply as an OpenAI-style model list ({"data":[{"id":...}]}, at most 1 MiB): a 2xx list with entries means the gateway accepted the assertion, and the command prints how many models the gateway authorises for <owner/repo> and their ids (the first 20, with JWT-shaped values redacted, control characters replaced by ? and every :: printed as : : so an id cannot form a workflow command); an empty list means the assertion was authenticated but no models are authorised for the repository, which is an error; 401 or 403 means the gateway refused the assertion; 3xx is an error (redirects are not followed); any other status (for example 404, 405, 429 or 5xx), or a 2xx reply that is not a model list, means authentication could not be confirmed, which is also an error. The request goes out over https only, ignores proxy settings, and refuses to connect to loopback, private or other internal addresses. The assertion is never printed. Outside Actions, it says so and stops at the config checks.
fullsend inference gateway status <owner/repo> \
[--fullsend-dir ".fullsend"]| Flag | Default | Description |
|---|---|---|
--fullsend-dir | .fullsend | Path to the .fullsend configuration directory |
See also
- Getting inference for fullsend — getting started guide
- OpenAI Workload Identity — end-to-end OpenAI WIF setup guide
- Advanced setup — non-standard installation paths and WIF configuration
- CLI internals — command tree and implementation details
