ci: remove public DigitalOcean automation#1010
Conversation
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Pull request overview
This PR removes provider-specific (DigitalOcean) automation from the public repository’s GitHub Actions surface and replaces it with a credential-free, least-privilege “public workflow policy” gate backed by a pinned analyzer + explicit allowlists (actions/commands/executables/presence).
Changes:
- Remove DigitalOcean conformance/budget/leak-scrubber/dispatch automation and related secret/callback authority from public workflows.
- Add a trusted-base
pull_request_targetpolicy workflow + verifier tooling, plus fixtures and mutation harness to enforce a fail-closed boundary. - Tighten remaining workflows to use GitHub-hosted runners, SHA/digest-pinned actions,
github.token(not named secrets), and explicit job-scoped permissions.
Reviewed changes
Copilot reviewed 60 out of 62 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/fixtures/public-workflow-policy/reject.yml | Negative fixture: forbidden patterns |
| scripts/fixtures/public-workflow-policy/reject-yaml-structure.yml | Negative fixture: YAML aliases/dupes |
| scripts/fixtures/public-workflow-policy/reject-unsafe-programs.yml | Negative fixture: dynamic/provider tools |
| scripts/fixtures/public-workflow-policy/reject-unreviewed-uses.yml | Negative fixture: unapproved uses: |
| scripts/fixtures/public-workflow-policy/reject-statement-authority.yml | Negative fixture: unsafe shell shapes |
| scripts/fixtures/public-workflow-policy/reject-shell.yml | Negative fixture: shell selection |
| scripts/fixtures/public-workflow-policy/reject-shell-inheritance.yml | Negative fixture: inherited shells |
| scripts/fixtures/public-workflow-policy/reject-secret-syntax.yml | Negative fixture: secret selector forms |
| scripts/fixtures/public-workflow-policy/reject-script-execution.yml | Negative fixture: committed script exec |
| scripts/fixtures/public-workflow-policy/reject-runners.yml | Negative fixture: runner selectors |
| scripts/fixtures/public-workflow-policy/reject-provider-uses.yml | Negative fixture: provider actions/reuse |
| scripts/fixtures/public-workflow-policy/reject-permissions.yml | Negative fixture: permission shapes |
| scripts/fixtures/public-workflow-policy/reject-missing-shell.yml | Negative fixture: implicit shell |
| scripts/fixtures/public-workflow-policy/reject-legacy-github-token.yml | Negative fixture: secrets.GITHUB_TOKEN |
| scripts/fixtures/public-workflow-policy/reject-implicit-permissions.yml | Negative fixture: implicit perms |
| scripts/fixtures/public-workflow-policy/reject-guard-suffix.yml | Negative fixture: guard bypasses |
| scripts/fixtures/public-workflow-policy/reject-global.yml | Negative fixture: global markers |
| scripts/fixtures/public-workflow-policy/reject-execution-context.yml | Negative fixture: exec context overrides |
| scripts/fixtures/public-workflow-policy/reject-env-indirection.yml | Negative fixture: env indirection |
| scripts/fixtures/public-workflow-policy/reject-dynamic-secrets.yml | Negative fixture: dynamic secret selectors |
| scripts/fixtures/public-workflow-policy/reject-deny-pattern-execution.yml | Negative fixture: deny-pattern exec |
| scripts/fixtures/public-workflow-policy/reject-command-analysis.yml | Negative fixture: command wrappers |
| scripts/fixtures/public-workflow-policy/reject-builtin-wrapper.yml | Negative fixture: builtin tunneling |
| scripts/fixtures/public-workflow-policy/pass.yml | Positive fixture: credential-free |
| scripts/fixtures/public-workflow-policy/pass-negative-guard.yml | Positive fixture: safe provider guard |
| scripts/fixtures/public-workflow-policy/pass-expression-and-deny-guard.yml | Positive fixture: safe expressions |
| scripts/fixtures/public-workflow-policy/lifecycle-old.yml | Fixture: lifecycle transition |
| scripts/fixtures/public-workflow-policy/lifecycle-future.yml | Fixture: lifecycle transition |
| scripts/check-public-workflow-policy.sh | Policy wrapper + policytool integrity |
| scripts/test-check-public-workflow-policy.sh | Mutation/lifecycle harness for policy |
| docs/WFCTL.md | Update infra cleanup guidance |
| docs/public-workflow-policy.md | Document new public policy model |
| docs/conformance-runbook.md | Remove DO operational runbook |
| .github/workflows/test-dispatch.yml | Remove repo-dispatch test workflow |
| .github/workflows/scripts/verify-public-workflow-branch-protection.sh | Add branch/tag governance verifier |
| .github/workflows/scripts/file-or-comment-leak-issue.sh | Remove DO leak/budget dedup helper |
| .github/workflows/release.yml | Reduce auth scope; add tag ancestry check |
| .github/workflows/public-workflow-policy.yml | Add trusted-base policy enforcement workflow |
| .github/workflows/pre-release.yml | Reduce auth scope; use github.token |
| .github/workflows/policytool/main.go | Add policy analyzer implementation |
| .github/workflows/policytool/main_test.go | Add analyzer test suite |
| .github/workflows/policytool/go.mod | Add isolated Go module for analyzer |
| .github/workflows/policytool/go.sum | Add analyzer dependency lock data |
| .github/workflows/osv-scanner.yml | Replace reusable wf with digest-pinned container steps |
| .github/workflows/helm-lint.yml | Add explicit default shell |
| .github/workflows/dependency-update.yml | Move write perms to job scope; use github.token |
| .github/workflows/cross-plugin-build-test.yml | Remove private Go module env; set default shell |
| .github/workflows/create-release.yml | Remove manual tag-and-dispatch workflow |
| .github/workflows/copilot-setup-steps.yml | Remove private repo Go config step |
| .github/workflows/conformance-smoke.yml | Remove DO conformance smoke workflow |
| .github/workflows/conformance-leak-scrubber.yml | Remove DO leak scrubber workflow |
| .github/workflows/conformance-budget-check.yml | Remove DO budget kill-switch workflow |
| .github/workflows/codeql.yml | Reduce global perms; set default shell; use github.token |
| .github/workflows/ci.yml | Add policy job; remove named-secret token paths |
| .github/workflows/benchmark.yml | Use pinned benchstat; set default shell |
| .github/public-workflow-secret-allowlist.json | Add empty secret allowlist |
| .github/public-workflow-presence-allowlist.json | Add presence inventory + tombstones |
| .github/public-workflow-executable-allowlist.json | Add executable allowlist entries |
| .github/public-workflow-command-allowlist.json | Add exact statement/command allowlist |
| .github/public-workflow-authority.json | Add policy authority bundle manifest |
| .github/public-workflow-action-allowlist.json | Add action allowlist with SHA/node/context digests |
| .github/conformance/cleanup.yaml | Remove DO cleanup IaC config |
⏱ Benchmark Results✅ No significant performance regressions detected. benchstat comparison (baseline → PR)
|
Text matching missed valid Go import syntax and rejected policy data. Parse Go and module files so only actual provider dependencies fail.
Candidate-controlled archive entries and analyzer-root symlinks must be rejected before extraction or trusted code execution. SDK policy markers are fixed substrings, not URL-validation regexes.
Exercise sibling path escapes, gitlinks, and hardlink archives so bootstrap validation cannot regress to type-specific or post-extraction checks.
Avoid recompiling the same digest validation regexp in manifest loops while preserving the exact lowercase-hex contract.
Pin active toolchains to Go 1.26.5 for the July stdlib security fixes. Treat only missing snapshot releases and tags as idempotent; all other GitHub API failures remain fatal.
Require the cleanup fake to match the exact default-GET release listing so unrelated paginated API calls cannot satisfy it.
Validate the complete release listing before deletion and enforce exact gh DELETE calls so malformed data cannot cause partial cleanup.
Scan the actual gitless archive tree and hidden workflow files without relying on ripgrep. Fail closed when archive enumeration or batched scanning cannot complete.
Run batched scans without ripgrep and isolate worker execution from hostile shell functions and PATH shims. Preserve fail-closed behavior for scan and fixture failures.
What changed
github.token, with explicit effective least-privilege permissionsWhy
Workflow is the provider-neutral framework. DigitalOcean ownership and any live provider validation belong in the DigitalOcean plugin repository, and public repositories must not dispatch workloads to private/self-hosted infrastructure or hold cloud credential authority.
This is the bootstrap policy PR. The trusted-base policy and required branch check will be enabled on
mainimmediately after merge.Impact
No Workflow package/API release is created by this CI-only change. Provider-specific runtime migration follows in separate locked PRs. Public Actions remain available without named secrets or live cloud access.
Validation
./scripts/check-public-workflow-policy.sh(11 workflows)go test -count=1 -race ./...,go vet ./..., and clean buildbash -n, JSON parsing, andgit diff --checkGOWORK=off GOFLAGS=-mod=readonly go test -count=1 -p=1 ./...CI follow-up evidence
The first PR run exposed a real differential OSV finding in the new isolated policy tool: Go 1.26.4 included GO-2026-4970 and GO-2026-5856. Active/current repository toolchain declarations now use Go 1.26.5, and a fresh policytool
govulncheck ./...reports no vulnerabilities.Review also identified a list/delete race in snapshot cleanup. Cleanup now enumerates release IDs through the GitHub API, validates the entire result before mutation, deletes both releases and encoded Git tag refs, treats only HTTP 404 as an already-completed concurrent deletion, and propagates authorization, rate-limit, server, malformed-status, list, and tag failures.
TDD regression proof:
Additional causal mutations proved that removing
--include, using raw#/%//tag paths, changing the exact list endpoint, or processing a valid row before a later malformed row all fail the harness.CI portability regression evidence
The prior GitHub-hosted policy job failed because the mutation harness invoked
rg, which is not installed on the stock runner. The harness now uses NUL-safe batchedfind/grep/xargsscans and executes workers through fixed absolute Bash andenv -i, without runtime ripgrep or ambient shell-function/PATH authority.Additional TDD regressions proved the replacement fails closed for directory-vs-file pruning, hostile PATH Bash/
trueshims, exported shell functions, malformed or empty sidecars, missing tools, scan errors, and errors in later batches.Doc-reconciliation: clean