Skip to content

Add a reusable workflow for manual secret writes - #53

Open
lowie27 wants to merge 1 commit into
v1from
feature/manual-secrets
Open

lowie27 wants to merge 1 commit into
v1from
feature/manual-secrets

Conversation

@lowie27

@lowie27 lowie27 commented Aug 24, 2026

Copy link
Copy Markdown

Everything about using this workflow is in Docs/infra-secret-write.md, added in this PR. What
follows is only what a reviewer needs and that page does not carry.

The diff

Path What
.github/workflows/infra-secret-write.yml the reusable workflow, three jobs
.github/actions/infra/secrets/preflight/action.yml validates and proves the write can succeed
.github/actions/infra/secrets/write/action.yml wraps the script
.../secrets/write/scripts/manual_secrets.sh the read-merge-write, usable standalone
Docs/infra-secret-write.md reference page, matching the other workflows
README.md one row in the workflow index

The Scaleway credential, an accepted risk

Both Scaleway jobs use the caller's repo-level SCALEWAY_ACCESS_KEY, the Terraform credential. A
scoped one was considered and not built: it would not be an access control, since a branch that
deletes needs: approval can reference the same key directly. What it buys is blast radius, and this
job needs "create one secret version" while holding a key that can destroy the estate. Worth deciding
now that this is shared rather than sandbox code.

Why there is an approval gate

The workflow exists so a developer can write a secret without holding a Scaleway credential. That
delegation is the point and also the risk: without a gate, anyone who can dispatch writes any value
into any environment, production included. The gate puts a second person on the decision and leaves a
record of who asked and who agreed.

trstringer/manual-approval reports a transient API error as a human denial and leaves its issue
open, which is why the job carries two compensating steps rather than one. Polling is 90 seconds
because its pending loop skips its own sleep; fix submitted upstream as
trstringer/manual-approval#236.

Known limitations

  • Any action in the job can read the value. It is a workflow_dispatch input, so it sits in
    $GITHUB_EVENT_PATH for the life of the job, readable by every step including third-party actions
    on moving tags. Masking is a display control, not access control. The only real close is the
    plaintext never being an input; the jq -n in the write action is the seam for that.
  • Who may approve is not decided. approvers is a required input with no default, and
    exclude-workflow-initiator-as-approver is false, so a caller listing only itself self-approves.
    Enabling that flag needs the list widened first, or it removes the only approver and the job
    reports a timeout. This PR needs an answer: who is on that list for real environments?
  • Invalid keys already in the secret are warned about, not refused. Scaleway does not validate
    key names, so a foo-bar added by hand in the console is storable. envFrom skips such a key and
    the pod never sees it, so the script carries it through and says so rather than blocking a write it
    did not cause. A key the caller is adding is still refused.

@lowie27 lowie27 added the ✨ enhancement New feature or request label Aug 24, 2026
@lowie27 lowie27 self-assigned this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant