Skip to content

ci: adopt gt repo governance and move the CI jobs into it - #48

Merged
pedromvgomes merged 4 commits into
mainfrom
chore/gt-repo-governance
Aug 22, 2026
Merged

ci: adopt gt repo governance and move the CI jobs into it#48
pedromvgomes merged 4 commits into
mainfrom
chore/gt-repo-governance

Conversation

@pedromvgomes

@pedromvgomes pedromvgomes commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Onboards this repository onto gt's governance subsystem
(pedromvgomes/gt#31).

Important

Do not merge before gt v1 is cut. Every rendered caller pins
pedromvgomes/gt@v1, which does not exist yet.

Dependabot

Both ecosystems unchanged — verified by parsing both files and diffing on
(ecosystem, directory): nothing added, nothing dropped. Cooldown 5 → 7
days, PR limit → 25, prefixes → build(deps): / ci(deps): with
include: scope.

This repository also gains the daily auto-merge batch for patch and
minor bumps, which it did not have.

bulwark is on

No security scanning here today, so gt's stage is an addition rather than a
duplicate. Expect findings on the first run; nothing gates on them while
ci-gate is not the required check.

CD is off — and needs a decision, not just a migration

release.yml fires on v*, while gt's cd-orchestration would claim
v*.*.*. Those are not the same set: v* also matches v2, v1.2, and
prerelease shapes. Which pattern is right belongs in the PR that turns CD
on, not this one, so it is recorded as a note: in the spec rather than
silently resolved.

verify-attestation also runs with require: true, and no tree carries an
attestation yet.

Inert

The ci-* stages land as empty no-ops; end2end is omitted, there being no
e2e suite. ci.yml keeps running and branch protection is unchanged.

Onboards this repository onto gt's governance subsystem
(pedromvgomes/gt#31). A committed .gt-repo.yaml is the source of truth and
`gt repo sync` renders the files from it.

Must not merge before gt v1 is cut: every rendered caller pins
pedromvgomes/gt@v1, which does not exist yet.

Both ecosystems are unchanged — nothing added, nothing dropped. Cooldown
moves 5 days to 7, the PR limit becomes 25, and prefixes become
build(deps)/ci(deps) with include: scope. This repository also gains the
daily auto-merge batch for patch and minor bumps, which it did not have.

bulwark is on. There is no security scanning here today, so gt's stage is an
addition rather than a duplicate.

CD is off, and here it needs a decision rather than just a migration:
release.yml fires on `v*` while gt's cd-orchestration would claim `v*.*.*`.
Which pattern is right is a question for the PR that turns CD on, not this
one. Recorded as a note in the spec so it is not rediscovered.

The ci-* stages land as empty no-ops and end2end is omitted, there being no
e2e suite. ci.yml keeps running and branch protection is unchanged.

Claude-Session: https://claude.ai/code/session_01PvwKxJ5vnqa9h9XXyTEj43
Picks up pedromvgomes/gt#31's annotation. semgrep's secrets-inherit rule
flagged the rendered orchestrator; gt cannot enumerate a repository's secret
names, so the reasoning is recorded at each site rather than the rule being
silenced.

Claude-Session: https://claude.ai/code/session_01PvwKxJ5vnqa9h9XXyTEj43
The first version of this PR landed the ci-* stages as empty no-ops beside a
ci.yml that still did all the work — two pipelines, and a ci-gate green on
the one running nothing.

All three jobs move, verbatim with their comments:

  lint, build  -> ci-build
  test         -> ci-test

lint and build share a stage because they answer the same question: does this
tree compile and conform. Splitting them across build and a stage of their
own would serialise two jobs that have no dependency on each other.

ci-test also gains a coverage profile, uploaded as gt-coverage. .bulwark.yml
here declares `coverage.source: report`, and bulwark exits rather than
shrugging when told to read a report nothing wrote — the trap gt hit on
itself and cubit hit after it.

The `configure git` step moves with the test job. Its comment explains why it
exists: the sourcestore and CLI tests shell out to git against file://
fixture repos, and `git init -b main` has to match local dev.

Verified that every job on main is accounted for and nothing references the
deleted file.

Claude-Session: https://claude.ai/code/session_01PvwKxJ5vnqa9h9XXyTEj43
@pedromvgomes
pedromvgomes force-pushed the chore/gt-repo-governance branch from 172827d to 9565a06 Compare August 21, 2026 15:14
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

bulwark

  • scan — no findings

  • coverage — go: 6.0% (baseline 6.0%); go patch: 9.5% (4/42 new lines; baseline 6.0%)

📦 Full bulwark output — complete scan and coverage logs.

@pedromvgomes pedromvgomes changed the title chore(ci): adopt gt repo governance ci: adopt gt repo governance and move the CI jobs into it Aug 21, 2026
Onboarding this repo to bulwark surfaced 45 gosec findings and 2 semgrep
ones. Two are real; the rest are what a CLI whose job is reading
user-named paths and shelling out to git always produces.

Real:

  - .github/workflows/{ci-build,ci-test,release}.yml pinned six actions to
    mutable @v7 / @v7.2.3 tags. A tag can be silently repointed by its
    owner — the trivy-action and kics-github-action compromises are exactly
    this. All six now pin the 40-char SHA, resolved from the GitHub API and
    matching what gt and the other governed repos already use. release.yml
    was not in the diff semgrep scanned, so nothing would have flagged it;
    it is also the workflow holding the release token.

  - updatestate and the sourcestore cache created 0755 directories and
    0644 files. Both live under XDG paths and belong to agtk alone, so
    they are now 0700/0600 — the same reasoning gt applied to its own
    config and update state.

The other 43 are annotated one by one with the reason they are not
defects, never disabled globally, so the next genuine finding in the same
file still surfaces:

  - G304 on ten reads: agtk reads the stack file, lockfile, settings and
    CLAUDE.md that the invoker points it at. That is the command.
  - G301/G306 on fifteen writes: 0755/0644 is intended. These are files
    agtk writes into the user's repo or shell config — .claude assets,
    agentic.yaml, agentic.lock, completions — meant to be committed and
    read by editors, shells and Claude itself. 0600 would break that.
  - G204/G702/G703 on four call sites: the git argv is built in-package,
    and defaultRun's exe is agtk's own os.Executable while shell is gated
    to bash/zsh/fish by supportedShell before the exec is reached.
  - G104 on nine: best-effort cleanup, where the error already being
    returned is the one that matters.

semgrep needed its own directive on the exec — #nosec is gosec-only, and
semgrep anchors to the finding line rather than the declaration.

Verified by running bulwark locally: gosec, govulncheck and semgrep all
pass, 39 nosec and 0 issues, with the build, vet, gofmt and the full
suite still green.

Claude-Session: https://claude.ai/code/session_01PvwKxJ5vnqa9h9XXyTEj43
@pedromvgomes
pedromvgomes merged commit 734209b into main Aug 22, 2026
10 checks passed
@pedromvgomes
pedromvgomes deleted the chore/gt-repo-governance branch August 22, 2026 04:20
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