From e29b8141f8195b74a62a6b40a90c836a1df4c1c2 Mon Sep 17 00:00:00 2001 From: Felix Faerber Date: Tue, 15 Sep 2026 10:09:19 +0300 Subject: [PATCH] Let caller-provided skills receive their secrets again #122 gave the reusable workflow an explicit workflow_call secret contract so XAI_API_KEY would stop arriving empty. That fixed the model key and quietly broke every caller-provided skill: SECRETS_JSON is toJSON(secrets), so it now contains only the secrets this contract declares, and a skill's setup.sh finds nothing under the names its own repo uses. homelab's node1-ssh skill is the live casualty. Its setup.sh reads SWARM_HOST, SWARM_USER and SSH_PRIV_KEY_B64, takes the "not set -- skipping node1 SSH alias" path, and exits 0; the agent then loads the skill, is told it may run `ssh node1 ...`, and gets nothing. @senior hit exactly this while diagnosing the immich crash-loop in homelab #301 and had to fall back to a blind version revert. The failure is silent by design -- the skip is what lets a fork run without deploy secrets -- so nothing in the run says the capability is gone. Declaring the three optional here is the smallest fix that keeps the contract. It is not a general one: secret names for caller skills are by definition known only to the caller, and an explicit contract cannot express that, so each new caller-skill secret has to be added alongside these. Also fixes two pieces of drift that would spread the same breakage: the header still told callers to use `secrets: inherit`, and README's copy-me stub still showed it, so the next repo onboarded would have arrived with no model key. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CYFnHida4AdiNDek2pzgXx --- .gitea/workflows/agent.yml | 14 +++++++++++++- .gitea/workflows/ai-agent.yml | 5 +++++ README.md | 7 ++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/agent.yml b/.gitea/workflows/agent.yml index a329ede..0437236 100644 --- a/.gitea/workflows/agent.yml +++ b/.gitea/workflows/agent.yml @@ -1,6 +1,7 @@ name: agent # Reusable AI-agent workflow, shared across repos. A caller repo triggers on issue_comment/issues -# and invokes this via: uses: gitea/agents/.gitea/workflows/agent.yml@main (secrets: inherit). +# and invokes this via: uses: gitea/agents/.gitea/workflows/agent.yml@main (explicit secret map, +# see .gitea/workflows/ai-agent.yml for the stub every caller copies). # The gate + steps run in the caller's event context (github.event.* / github.repository are the caller's). on: workflow_call: @@ -29,6 +30,17 @@ on: required: false TOKEN_INTERN: required: false + # Secrets for caller-provided skills (.gitea/agent-skills//setup.sh). Their names are + # known only to the caller repo, but SECRETS_JSON below is toJSON(secrets) and can therefore + # only ever contain what this contract declares — so every such secret has to be listed here, + # optional, or the skill silently no-ops and the agent loses the capability without an error. + # These three are homelab's node1-ssh skill; add further caller-skill secrets alongside them. + SWARM_HOST: + required: false + SWARM_USER: + required: false + SSH_PRIV_KEY_B64: + required: false # Pinned opencode version — used to install it and to key the CI cache below. env: diff --git a/.gitea/workflows/ai-agent.yml b/.gitea/workflows/ai-agent.yml index 803ca3b..8cbea77 100644 --- a/.gitea/workflows/ai-agent.yml +++ b/.gitea/workflows/ai-agent.yml @@ -26,3 +26,8 @@ jobs: TOKEN_QA: ${{ secrets.TOKEN_QA }} TOKEN_OPS: ${{ secrets.TOKEN_OPS }} TOKEN_INTERN: ${{ secrets.TOKEN_INTERN }} + # Secrets for this repo's own caller-provided skills (.gitea/agent-skills/). Unset in a repo + # that ships no such skill, which is harmless: the skill's setup.sh no-ops on an empty value. + SWARM_HOST: ${{ secrets.SWARM_HOST }} + SWARM_USER: ${{ secrets.SWARM_USER }} + SSH_PRIV_KEY_B64: ${{ secrets.SSH_PRIV_KEY_B64 }} diff --git a/README.md b/README.md index 7d73bbe..9d754ee 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,12 @@ on: jobs: agent: uses: gitea/agents/.gitea/workflows/agent.yml@main - secrets: inherit + # Explicit map, not `secrets: inherit`: inherit alone has left XAI_API_KEY empty on some Gitea + # cross-owner calls. Copy the full list from .gitea/workflows/ai-agent.yml, which is the stub + # this file abbreviates -- a secret missing from the map does not reach the workflow at all. + secrets: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + # ... and the OLLAMA_*, XAI_API_KEY, TOKEN_* and caller-skill entries, verbatim. ``` That's the whole per-repo footprint, and it's the minimum a caller can be: the `on:` triggers must