Skip to content

ci: guard publish, release, deploy and badge jobs to the upstream repository - #51

Merged
adminopenclaw8-sketch merged 1 commit into
masterfrom
codex/ci-guard-fork-side-effects
Sep 13, 2026
Merged

adminopenclaw8-sketch merged 1 commit into
masterfrom
codex/ci-guard-fork-side-effects

Conversation

@adminopenclaw8-sketch

Copy link
Copy Markdown
Collaborator

Problem

dborup/CoreScope runs the same workflows as upstream Kpa-clawbot/CoreScope. As they stand on master (fda24ca5), a run on this fork would try to do everything upstream does:

Event on dborup/CoreScope External side effects that would run
push to master, e.g. merging any PR GHCR login + multi-arch build-push-action (push: true, GHA cache write), Deploy Staging on [self-hosted, meshcore-runner-2] (docker compose … up -d), badge commits to master via the Contents API with BADGE_PUSH_TOKEN
workflow_dispatch on master Deploy Staging
workflow_dispatch on a v* tag, including the fast-path fallback dispatch release-artifacts: softprops/action-gh-release with contents: write
push of a v* tag release-fast-path: GHCR login, crane tag, gh workflow run deploy.yml

The only thing that stops this chain today is a failing test step in "Go Build & Test". That is not protection.

Change

github.repository == 'Kpa-clawbot/CoreScope' is ANDed with the existing condition of every job or step that has an external side effect. No existing condition is replaced.

.github/workflows/deploy.yml

  • build-and-publish, step level: the five publish steps are Set up Docker Buildx, Set up QEMU, Log in to GHCR, Extract Docker metadata and Build and push to GHCR. Each is now if: github.event_name == 'push' && github.repository == 'Kpa-clawbot/CoreScope'.
    • The job itself and its Build Go Docker image (local staging) step stay unguarded, so the image build still validates on the fork.
    • The job stays in the needs chain unchanged.
  • release-artifacts, job level: startsWith(github.ref, 'refs/tags/v') && github.repository == 'Kpa-clawbot/CoreScope'.
  • deploy, job level: the existing push/dispatch + refs/heads/master condition gets && github.repository == 'Kpa-clawbot/CoreScope'. Because the guard is at job level, the self-hosted deploy job is never even scheduled on the fork.
  • publish, job level: github.event_name == 'push' && github.repository == 'Kpa-clawbot/CoreScope'.
  • A short header comment explains the guard.

.github/workflows/release-fast-path.yml

  • retag-or-fallback, job level: if: github.repository == 'Kpa-clawbot/CoreScope'. This covers the GHCR re-tag and the gh workflow run deploy.yml fallback dispatch.

cmd/server/fork_guard_workflow_test.go (new; test only, same text-based "config gate" pattern as release_fast_path_workflow_test.go). It pins:

  • the guard on the four side-effect jobs, while their original conditions are kept;
  • the guard on all five publish steps, the local build step staying unguarded, and build-and-publish staying unconditional at job level;
  • go-test and e2e-test having no job condition and no repository guard.

Not changed: triggers, permissions, secrets, runners, environments, concurrency, test steps, CI artifact uploads (upload-artifact of the badge JSON), the squad workflows, production code, Dockerfiles and Go versions.

Event / repository matrix

Job if: expressions were evaluated from the parsed YAML for each case, following needs. Every non-skipped predecessor is assumed to succeed, so the result does not depend on tests failing. GitHub's case-insensitive string comparison is used.

GHCR = the five publish steps inside build-and-publish. run / skip refer to jobs.

dborup/CoreScope

Event before (fda24ca5) after
pull_request → master go-test, e2e-test, build-and-publish run (no GHCR); release-artifacts, deploy skip; publish skip (needs) same
push master go-test, e2e-test, build-and-publish + GHCR, deploy run, publish run go-test, e2e-test, build-and-publish run (no GHCR); release-artifacts, deploy skip; publish skip (needs)
workflow_dispatch master tests + build; deploy run tests + build; deploy skip; publish skip
workflow_dispatch v* tag tests + build; release-artifacts run tests + build; release-artifacts skip
push v* tag deploy.yml not triggered; release-fast-path retag-or-fallback run deploy.yml not triggered; retag-or-fallback skip

Kpa-clawbot/CoreScope

The evaluated output is identical before and after for all five events:

  • pull_request: tests and build, no GHCR, no deploy.
  • push master: tests, build + GHCR, deploy and publish.
  • dispatch on master: deploy.
  • dispatch on a v* tag: release-artifacts.
  • push of a v* tag: retag-or-fallback.

The fork's go-test, e2e-test and build-and-publish statuses are unchanged for every event; no test job becomes skipped because a publish job is skipped.

Other workflows

These do not deploy, publish images or releases, or push files, so they are unchanged here. Their remaining external writes are listed for a separate decision:

  • squad-heartbeat (schedule every 30 min, issues closed/labeled, PR closed, dispatch): adds labels and comments to issues, and assigns Copilot when .squad/team.md opts in.
  • squad-triage and squad-issue-assign (issues labeled): add labels, comments and assignees.
  • sync-squad-labels (push touching .squad/team.md or .ai-team/team.md, dispatch): creates and updates labels.

No reusable workflows (workflow_call), composite actions or pull_request_target exist, and none of the scripts invoked by the workflows push, publish or deploy.

Verification

  • YAML: all 6 workflow files parse (Ruby Psych). actionlint/yamllint are not available locally, so GitHub-specific expression linting was not run beyond evaluating the job and step conditions above.
  • Config-gate tests: cd cmd/server && go test -run 'TestForkGuard|TestReleaseFastPathWorkflowExists|TestDeployWorkflowNoLongerTriggersOnTags' passes all 5 tests.
  • Negative controls, each reverting one guard:
    • dropping the deploy guard, un-guarding Log in to GHCR, repository-guarding go-test, dropping the fast-path guard, or replacing (instead of ANDing) the publish condition each make the new test fail with a specific message;
    • the files were restored byte-identically afterwards.
  • Static checks: go vet ./... (cmd/server) passes, gofmt -l is clean and git diff --check is clean.
  • Diff scope: exactly the 3 files above, with no permissions, runs-on, secrets., environment: or trigger lines touched.
  • Toolchain: local Go 1.27.0; the module still declares its own version, unchanged.
  • Nothing real was exercised: no deploy, publish, release or push step was run as a test.

CI on this PR

Opening this PR triggers only CI/CD Pipeline on pull_request (no types: filter, so opened / synchronize / reopened). For a same-repository PR that run uses the workflow as it exists on this PR's merge ref, i.e. with the guards. None of the side-effect jobs or steps can run for a pull_request event either before or after this change.

Expected result: "Go Build & Test" still fails on the documented baseline TestPruneOldNeighborMetrics, because PR 33 is not merged yet. Downstream jobs are skipped. This PR does not claim green CI.

Limitations

  • A guard only protects runs whose workflow revision contains it. A workflow runs from the revision of the ref being built:
    • a v* tag pushed to a commit that predates this change runs the old, unguarded release-fast-path.yml;
    • a manual workflow_dispatch against an old ref uses that ref's unguarded deploy.yml;
    • avoid both on this fork. Closing that gap completely needs Actions settings, which this PR does not touch.
  • The squad workflows' issue writes are unchanged (see above).
  • The matrix is a static evaluation of the conditions, not a live run on either repository.

Safe rollout (for the later merge decision)

  1. Merge this PR before PR 33. Merging it creates a push to master, and that push run uses the workflow file from the merge commit itself, so the guards already apply to that first run. On this fork it runs tests and the local image build only, with no GHCR, deploy or badges.
  2. Right before merging, confirm no CI/CD Pipeline run is queued or in progress from an older revision (gh run list --status queued / in_progress). At the time this PR was opened there were none, and no push-event run has ever happened on this fork.
  3. If an old-revision run is queued at that moment, stop and get a separate decision on cancelling it or pausing Actions. Neither is part of this PR.
  4. After it is merged, later merges such as PR 33 run with the guards in place.

🤖 Generated with Claude Code

…ository

The CI workflows are shared with Kpa-clawbot/CoreScope, where a push to
master publishes to GHCR, dispatch on a tag uploads release assets, the
staging job deploys via a self-hosted runner and the badge job commits
files to master. On a fork the same runs would attempt all of that, and
the only thing stopping it today is a failing test step.

Add `github.repository == 'Kpa-clawbot/CoreScope'`, ANDed with each
existing condition, to:
- deploy.yml: the five GHCR publish steps in build-and-publish (the
  local staging image build stays unguarded), and the release-artifacts,
  deploy and publish jobs (job level, so the self-hosted deploy job is
  never scheduled on a fork);
- release-fast-path.yml: the retag-or-fallback job (GHCR re-tag and the
  deploy.yml dispatch).

Tests, e2e and CI artifact uploads keep running on forks; upstream
behaviour is unchanged. A config-gate test pins the guards, the kept
conditions and the unguarded test jobs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adminopenclaw8-sketch
adminopenclaw8-sketch merged commit 8304e47 into master Sep 13, 2026
5 of 6 checks passed
adminopenclaw8-sketch pushed a commit that referenced this pull request Sep 14, 2026
…rl comments

Two review fixes on this PR.

1. CI registration. `test-issue-1890-og-url.js` was only wired into
   `test-all.sh` (used by `npm test`), not into the JS test step in
   `.github/workflows/deploy.yml`. CI could not catch a regression of
   the hardcoded og:url. Added `node test-issue-1890-og-url.js` to that
   step's existing list, directly before `test-issue-1375-scope-stats-
   fetch.js` (the test that currently stops the step). test-all.sh is
   unchanged; the registration there was already correct.

2. Comment accuracy, in `public/index.html` and
   `test-issue-1890-og-url.js`. The removed tag declared the upstream
   analyzer instance's own URL as the canonical URL for every
   self-hosted deployment (Kpa-clawbot#1890) -- correct metadata for upstream,
   wrong for everyone else. Reworded both comments to say that
   precisely, and to stop implying things not established:
   - og:url is metadata, not an HTTP redirect, and does not by itself
     decide what a viewer's click navigates to.
   - Per the Open Graph protocol it is a required property, not
     "optional" -- omitting it leaves the crawled URL as the fallback
     canonical reference, which is what actually fixes this for every
     instance.
   - This change does not refresh previews a consumer has already
     cached under the old, hardcoded value.
   No functional assertions changed in test-issue-1890-og-url.js --
   only the file-level comment. The `public/index.html` comment change
   had to avoid writing the literal removed domain: the test's own
   4th assertion scans the whole file for that string, and an earlier
   draft of this comment briefly reintroduced it and failed its own
   guard before landing on the current wording.

Verified on this branch's own base (pre-#51/#33 master) and against
a merge into current master: test-issue-1890-og-url.js passes 4/4 on
the resulting index.html and still fails 2/4 (og:url present, 00id.net
present) against the original hardcoded tag. The merge result's
deploy.yml differs from current master by exactly the one added test
line; release-fast-path.yml and cmd/server/fork_guard_workflow_test.go
are byte-identical to master, and all four #51 repository guards
(the five build-and-publish publish steps, release-artifacts, deploy,
publish, retag-or-fallback) are present in the merged file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant