Skip to content

ci(workflows): fix boj-build YAML + gate mirror secrets on presence#362

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/workflow-hardening-followup
Jun 3, 2026
Merged

ci(workflows): fix boj-build YAML + gate mirror secrets on presence#362
hyperpolymath merged 2 commits into
mainfrom
claude/workflow-hardening-followup

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Workflow hardening — round 2

Follow-up to #360, closing the remaining real workflow_audit findings (the rest were false positives — see below). Owner decisions: new separate job for boj-build, harden all 6 mirror jobs.

boj-build.yml — fix invalid YAML + correct the validation

The K9-SVC Validation and Contractile Check steps were indented at job level instead of step level, so the file was invalid YAML and GitHub could not load the workflow at all.

  • Moved both steps into a new ungated job validate-contractiles that runs on every push. (They validate this repo's contractile set, so they must not sit behind trigger-boj's if: BOJ_SERVER_URL configured guard.)
  • Both jobs gained timeout-minutes: 10.
  • The completeness check was also wrong: it hard-coded must trust dust lust adjust intend — but lust doesn't exist, bust was missing, and intend's file is Intentfile.a2ml (not Intendfile). It now reads the canonical verb set from the registry (.machine_readable/contractiles/INDEX.a2ml), exactly as INDEX instructs consumers to do — so it's correct now and self-maintaining as verbs change.
  • Verified green locally: all 6 canonical contractiles (adjust, bust, dust, intend, must, trust) present; script exits 0.

mirror-reusable.yml — secret-presence gate on the 6 SSH mirrors

The gitlab/bitbucket/codeberg/sourcehut/disroot/gitea jobs ran webfactory/ssh-agent with an inherited SSH key gated only on vars.<FORGE>_MIRROR_ENABLED. An enabled-but-unconfigured repo fed ssh-agent an empty key and failed. Applied the existing Radicle pattern already in this file:

  • gate the ssh-agent + push steps on secrets.<FORGE>_SSH_KEY != ''
  • add a Skipped (<FORGE>_SSH_KEY not configured) step on == '' that emits an actionable ::notice:: and ends the job cleanly.

On the findings not addressed (deliberately)

  • unpinned_action (governance-reusable.yml) — false positive. Every uses: is already pinned to a full 40-char SHA; Hypatia truncates it to @de0f in its own message.
  • missing_timeout_minutes on governance.yml / mirror.yml / scorecard.yml / secret-scanner.yml — false positives. These are reusable-workflow caller jobs; timeout-minutes is invalid on a uses: job. Their timeouts live in the called workflows (fixed in ci(workflows): add timeout-minutes to every job + fix changelog YAML #360 + here).
  • scorecard_publish_with_run_step (scorecard-enforcer.yml) — false positive. The scorecard job that publishes already contains only uses: steps; the run: steps are in separate jobs. Already compliant (the author documented the split).

Validation

  • All 28 workflows parse cleanly.
  • Every step-job has a timeout-minutes.
  • mirror-reusable: 15 != '' gates (6 ssh-agent + 6 push + 3 radicle) and 7 skip-notice steps.

🤖 Draft.

https://claude.ai/code/session_01XZhw6Fq27eoeyEB4LR3a2c


Generated by Claude Code

Follow-up to #360 (the remaining real workflow_audit items; owner chose
'new separate job' for boj-build and 'harden all 6' for the mirrors).

boj-build.yml — was invalid YAML: the 'K9-SVC Validation' and 'Contractile
Check' steps were indented at job level instead of step level, so GitHub
could not load the workflow at all. Moved them into a new ungated job
'validate-contractiles' that runs on every push (the trigger-boj job is
gated on BOJ_SERVER_URL, which must not gate repo self-validation). Both
jobs gained timeout-minutes: 10. The completeness check was also wrong
(hard-coded 'must trust dust lust adjust intend' — 'lust' does not exist,
'bust' was missing, and intend's file is Intentfile.a2ml not Intendfile);
it now reads the canonical verb set from the registry
(.machine_readable/contractiles/INDEX.a2ml), as INDEX itself instructs
consumers to do. Verified green locally: all 6 contractiles present.

mirror-reusable.yml — the six SSH-based mirror jobs (gitlab, bitbucket,
codeberg, sourcehut, disroot, gitea) ran webfactory/ssh-agent with an
inherited SSH key gated only on vars.<FORGE>_MIRROR_ENABLED, so an
enabled-but-unconfigured repo fed ssh-agent an empty key and failed.
Applied the existing Radicle pattern: gate the ssh-agent and push steps
on secrets.<FORGE>_SSH_KEY != '' and add a Skipped notice step on == ''
so the job ends cleanly with an actionable ::notice:: instead of erroring.

https://claude.ai/code/session_01XZhw6Fq27eoeyEB4LR3a2c
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

🔍 Hypatia Security Scan

Findings: 141 issues detected

Severity Count
🔴 Critical 64
🟠 High 56
🟡 Medium 21

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action for the check script)\n        uses: actions/checkout@de0f needs attention",
    "type": "unpinned_action",
    "file": "governance-reusable.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action for the check script)\n        uses: actions/checkout@de0f needs attention",
    "type": "unpinned_action",
    "file": "governance-reusable.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in governance.yml",
    "type": "missing_timeout_minutes",
    "file": "governance.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in mirror.yml",
    "type": "missing_timeout_minutes",
    "file": "mirror.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in scorecard.yml",
    "type": "missing_timeout_minutes",
    "file": "scorecard.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in secret-scanner.yml",
    "type": "missing_timeout_minutes",
    "file": "secret-scanner.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in scorecard-enforcer.yml",
    "type": "scorecard_publish_with_run_step",
    "file": "scorecard-enforcer.yml",
    "action": "split_scorecard_publish_job",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in codeql.yml",
    "type": "codeql_missing_actions_language",
    "file": "codeql.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Python file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/standards/standards/a2ml-templates/state-scm-to-v2.py",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/standards/standards/lol/test/vitest.config.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath marked this pull request as ready for review June 3, 2026 23:12
@hyperpolymath hyperpolymath enabled auto-merge (squash) June 3, 2026 23:12
hyperpolymath added a commit that referenced this pull request Jun 3, 2026
## Scan the `actions` language with CodeQL

Adds an `actions` entry to the CodeQL matrix (`build-mode: none`) so
CodeQL scans the repo's GitHub Actions workflow files for security
issues, alongside the existing `javascript-typescript` analysis.

Resolves the Hypatia `workflow_audit` finding
`codeql_missing_actions_language` (surfaced on #362 once the
medium-severity timeout noise was cleared).

```diff
         include:
           - language: javascript-typescript
             build-mode: none
+          - language: actions
+            build-mode: none
```

### Why a separate PR
Per owner request — this enables a **new analysis target**, isolated
from the workflow-hygiene work (#360, #362) so the new scan is easy to
review on its own. It may surface new code-scanning alerts on existing
workflows; those would be triaged normally.

### Also in this PR: registry sync (required to pass `registry-verify`)
This branch was cut before #356 + #361 landed on `main`. After merging
`main` in, the `registry-verify` gate failed because **`main`'s
committed `.machine_readable/REGISTRY.a2ml` is itself stale** — #361's
estate-wide workflow edits changed files under tracked spec-home dirs
without re-running `just registry`, leaving 9 `source_hash` entries out
of date. Regenerated deterministically via `scripts/build-registry.sh`;
`--check` now exits clean. (Heads-up: `main`'s own `registry-verify` is
likely red until this lands or a dedicated regen does.)

PR diff vs `main`: `codeql.yml` (+2) and the regenerated
`REGISTRY.a2ml`.

🤖 Draft.

https://claude.ai/code/session_01XZhw6Fq27eoeyEB4LR3a2c

Co-authored-by: Claude <noreply@anthropic.com>
Resolves a conflict in boj-build.yml: main's #361 fixed the malformed
workflow by DELETING the two orphaned steps, while this PR fixes them by
moving them into a new ungated 'validate-contractiles' job (the owner-
chosen approach). Kept this PR's validate-contractiles job and adopted
main's 'timeout-minutes: 10' on trigger-boj (removed the duplicate
timeout key the auto-merge produced).

Registry is in sync on the merge result (this PR touches no tracked spec
home); main's earlier registry drift was already cleared by #364/#366.

https://claude.ai/code/session_01XZhw6Fq27eoeyEB4LR3a2c
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

🔍 Hypatia Security Scan

Findings: 147 issues detected

Severity Count
🔴 Critical 64
🟠 High 62
🟡 Medium 21

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action for the check script)\n        uses: actions/checkout@de0f needs attention",
    "type": "unpinned_action",
    "file": "governance-reusable.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action for the check script)\n        uses: actions/checkout@de0f needs attention",
    "type": "unpinned_action",
    "file": "governance-reusable.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in governance.yml",
    "type": "missing_timeout_minutes",
    "file": "governance.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in mirror.yml",
    "type": "missing_timeout_minutes",
    "file": "mirror.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in scorecard.yml",
    "type": "missing_timeout_minutes",
    "file": "scorecard.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in secret-scanner.yml",
    "type": "missing_timeout_minutes",
    "file": "secret-scanner.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in scorecard-enforcer.yml",
    "type": "scorecard_publish_with_run_step",
    "file": "scorecard-enforcer.yml",
    "action": "split_scorecard_publish_job",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in instant-sync.yml",
    "type": "secret_action_without_presence_gate",
    "file": "instant-sync.yml",
    "action": "peter-evans/repository-dispatch",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Python file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/standards/standards/a2ml-templates/state-scm-to-v2.py",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/standards/standards/lol/test/vitest.config.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 33a82ee into main Jun 3, 2026
22 checks passed
@hyperpolymath hyperpolymath deleted the claude/workflow-hardening-followup branch June 3, 2026 23:18
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.

2 participants