Skip to content

fix(ci): correct publish workflow SHA pins (unblocks npm + JSR)#88

Merged
hyperpolymath merged 2 commits into
mainfrom
fix/publish-workflow-sha-pins
May 20, 2026
Merged

fix(ci): correct publish workflow SHA pins (unblocks npm + JSR)#88
hyperpolymath merged 2 commits into
mainfrom
fix/publish-workflow-sha-pins

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Both action SHA pins in `.github/workflows/publish.yml` resolved to nonexistent refs, causing every publish since v0.4.1 to fail at the action download stage (before any of our code ran):

Action Before After Cause
`actions/setup-node` v4.4.0 `49933ea5288caeca8642195f882660b323136e2a` `49933ea5288caeca8642d1e84afbd3f7d6820020` SHA suffix typo'd — first 19 chars match the real SHA, last 21 chars diverged
`denoland/setup-deno` v2.1.1 `909cc5acb0fdd60627fb858598190e9d10232b3a` `667a34cdef165d8d2b2e98dde39547c9daac7282` (v2.0.4) Tag v2.1.1 does not exist; highest available is v2.0.4

Re-verified both SHAs via `gh api repos///git/refs/tags/...`.

Evidence

Failed runs since the bad pins landed: 25013192716 (v0.4.6), 24738743650 (v0.4.1 retry), and earlier. Each errors with:

```
##[error]Unable to resolve action `actions/setup-node@49933ea...`, unable to find version
##[error]Unable to resolve action `denoland/setup-deno@909cc5ac...`, unable to find version
```

Why this matters

This is the actual gate on the Glama Quality C → A fix. npm has been stuck at v0.4.1 (with the v0.3.1-era stub tool descriptions) since the publish workflow broke. Tagging v0.4.7 with this fix in place will run the v0.4.7 publish to completion, which surfaces the AAA-tier tool descriptions to npm, which Glama then re-scans.

Test plan

  • CI green on this PR
  • Merge → tag `v0.4.7` → workflow runs to completion
  • `npm view @hyperpolymath/boj-server@latest version` returns `0.4.7`
  • JSR package updates to 0.4.7

🤖 Generated with Claude Code

Both action pins resolved to nonexistent refs, causing every release
since v0.4.1 to fail at action download. Two distinct errors:

- actions/setup-node v4.4.0 — SHA suffix was typo'd
  (49933ea...82660b323136e2a → correct 49933ea...d1e84afbd3f7d6820020)
- denoland/setup-deno v2.1.1 — tag does not exist; highest available is
  v2.0.4. Re-pinned to v2.0.4.

Re-verified both SHAs via `gh api repos/<owner>/<action>/git/refs/tags/...`.

Once merged, tagging v0.4.7 will trigger a successful npm + JSR publish —
which is the actual fix for Glama's Quality C score (npm is still on 0.4.1
with the v0.3.1-era stub tool descriptions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 29 issues detected

Severity Count
🔴 Critical 18
🟠 High 4
🟡 Medium 7

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stale AI session file -- delete",
    "type": "stale",
    "file": "GEMINI.md",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Python file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/.github/scripts/validate-eclexiaiser.py",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 20, 2026
…m 1) (#89)

## Summary

Closes the first item of epic #87. The bridge has been declaring
\`resources\` and \`prompts\` capabilities in its MCP \`initialize\`
response since v0.4.5, but never actually served any. This wires up real
handlers so clients can:

- **Inspect BoJ state without LLM round-trips** — cartridge index,
capability matrix, proof obligations via \`resources/read\`
- **Instantiate high-frequency multi-cartridge workflows** — six
BoJ-shaped templates via \`prompts/get\`

## Resources surface (6 URIs)

| URI | Content | Backend? |
|---|---|---|
| \`boj://cartridges\` | Full cartridge index | REST when live;
offline-menu fallback |
| \`boj://cartridges/<name>\` | Per-cartridge manifest | REST; name
validated against \`^[a-z0-9][a-z0-9-]*-mcp$\` |
| \`boj://capabilities/matrix\` | Protocol × domain grid | REST;
offline-hint fallback |
| \`boj://capabilities/tools\` | Bridge tools grouped by domain | Always
offline-readable |
| \`boj://proofs/manifest\` | P-01..P-07 + \`believe_me\` audit | Always
offline-readable |
| \`boj://server/info\` | Server identity + capabilities | Always
offline-readable |
| \`boj://docs/architecture\` | ADR + topology pointers (Markdown) |
Always offline-readable |

## Prompts surface (6 templates)

| Name | Composes |
|---|---|
| \`audit-repo\` | hypatia-mcp + panic-attack-mcp + secrets-mcp |
| \`convene-cluster\` | All \`coord_*\` tools — register, claim,
broadcast, supervise |
| \`deploy-with-dns-ssl\` | Provider cartridge
(fly/render/railway/vercel) + cloudflare-mcp |
| \`summarize-channel\` | slack/discord/matrix/telegram via
\`boj_cartridge_invoke\` |
| \`triage-issues\` | github-api-mcp / gitlab-api-mcp |
| \`proof-status\` | \`boj://proofs/manifest\` + \`boj://cartridges\`
(resource-first) |

Each template names the exact tools the LLM should call — no free-form
orchestration.

## What's in the diff

- **New** \`mcp-bridge/lib/resources.js\` (~200 LOC) — resource
definitions + URI router
- **New** \`mcp-bridge/lib/prompts.js\` (~200 LOC) — prompt definitions
+ argument validation + template builders
- **Edit** \`mcp-bridge/main.js\` — replaced empty list stubs with real
handlers; added \`resources/read\` and \`prompts/get\` methods; wired
error sanitization
- **Edit** \`mcp-bridge/tests/dispatch_test.js\` — 2 new coherence tests
covering resource/prompt well-formedness + error paths

## Verification

End-to-end with \`deno run -A mcp-bridge/main.js\` + manual JSON-RPC
fixtures:

- ✅ \`initialize\` → unchanged, declares same capabilities
- ✅ \`resources/list\` → returns 6 resources with proper schema
- ✅ \`resources/read\` → returns content for each URI; unknown URI →
\`-32602\`; non-\`boj://\` URI rejected
- ✅ \`prompts/list\` → returns 6 prompts with argument schemas
- ✅ \`prompts/get\` → valid args produce non-empty message; missing
required arg → \`-32602\`; unknown name → \`-32602\`
- ✅ Existing test suite: **11/11 pass** (no regressions)
- ✅ New tests: 2/2 pass (resources well-formedness + prompts
well-formedness + arg validation)

## Tier-payoff

This is the lowest-effort item in epic #87 Tier A and the highest
coherence payoff — BoJ becomes a fully realised MCP citizen (tools +
resources + prompts + logging), not just a tool surface.

## Sequencing

Independent of #88 (publish workflow fix) and of v0.4.7 tagging. Can
land at any time. Future cartridges may extend the resource catalogue
(e.g. \`boj://policies/...\` once item 4's policy DSL lands).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath merged commit b752a27 into main May 20, 2026
13 of 16 checks passed
@hyperpolymath hyperpolymath deleted the fix/publish-workflow-sha-pins branch May 20, 2026 06:30
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 29 issues detected

Severity Count
🔴 Critical 18
🟠 High 4
🟡 Medium 7

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stale AI session file -- delete",
    "type": "stale",
    "file": "GEMINI.md",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "medium"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Python file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/.github/scripts/validate-eclexiaiser.py",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 20, 2026
…(epic #87 items 4 + 10) (#92)

## Summary

Two coupled RFCs for epic #87 Tier B. Coupled because they share
trust-tier vocabulary — ADR-0008's submission protocol requires every
cartridge to ship a default policy bundle in the schema ADR-0007
defines.

**No code in this PR.** Pure design docs. Implementation tracked
separately in epic #87 (items 4 and 10).

## ADR-0007 — Trust-tier policy DSL

Adopt **Nickel** as the policy DSL (extends the existing
\`coord-messages.ncl\` investment), with a clean **PEP/PDP split**:

- **PEP** stays in \`mcp-bridge/main.js\` (where the existing
\`hardeningGate\` lives)
- **PDP** is a new \`policy-mcp\` cartridge that the bridge consults per
\`tools/call\`

Schema: per-cartridge × per-tool × \`{tier, rate_limit, required_role,
master_approval, allowed_args, side_effect}\`. Verdicts: \`allow\` /
\`deny\` / \`rate_limit\` / \`require_approval\` (the last routes
through \`coord_send_gated\`-style quarantine).

Default policy bundle covers all 41 bridge tools out of the box.
Migration sequence covered explicitly in the ADR's "Open questions"
section.

## ADR-0008 — Cartridge marketplace

**Activates the Ayo tier**, which currently has exactly one member and
no protocol. New repo \`hyperpolymath/cartridge-index\` holds signed
entries (ML-DSA-87 per EXHIBIT-B) pointing to source repos at
content-pinned revs.

Promotion path: outside → Ayo → Shield → Teranga. Promotion is recorded
in the index, not the source repo, so cartridges don't need to "know"
their tier.

Critically: respects ADR-0002 (BoJ-only MCP). Community capabilities
flow into BoJ as cartridges, **never as standalone MCPs**.

Default-safe posture: Ayo cartridges are visible via
\`boj_marketplace_search\` but never auto-loaded; user must explicitly
\`boj_marketplace_install --accept-ayo-tier\`.

## Why this pair, this order

The epic specifies they ship together: "Items 4 + 10 RFCs together (they
share the trust-tier vocabulary)." 0007 defines what a policy bundle
looks like; 0008 requires every submission to ship one. Either alone
leaves a hole.

## Review focus

The ADRs are formatted for substantive engagement, not rubber-stamp.
Each has explicit:

- **Consequences (positive + negative)** — not just "this is good"
- **Non-goals** — what we deliberately won't do
- **Open questions** — decisions explicitly deferred to implementation

Recommend reading the **Open questions** sections — that's where the
load-bearing choices that need your call live.

## What this doesn't change

- No code touched.
- No existing cartridges affected.
- ADR-0002 stands; this RFC pair operates strictly within its
constraints.

## Sequencing

Per epic #87: this is Tier B step 1 of 3. Next pair (items 2 + 3:
sandbox cartridge + cross-machine federation) follows in a sibling PR;
the third pair (items 5 + 6: webhooks + sampling) after that. All three
pairs are independent of each other and of the code PRs (#88/#89/#91).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request May 20, 2026
…epic #87 items 2 + 3) (#93)

## Summary

Second coupled RFC pair for epic #87 Tier B. Coupled because
**sandbox-mcp is machine-local by construction** and the federation
design must remain aware of that — federation coordinates *which peer
runs a sandbox*; sandbox handles themselves never cross machines.

**No code in this PR.** Pure design docs.

## ADR-0009 — Sandbox cartridge

Multi-provider, tier-gated code execution as **one MCP cartridge** with
five swappable backends:

| Backend | Isolation | Cold-start | When |
|---|---|---|---|
| \`local\` | Process (bubblewrap) | <100ms | Default; no SaaS
dependency |
| \`e2b\` | Firecracker microVM | ~500ms | Best LLM-coding ergonomics |
| \`modal\` | Container | ~1s | Persistent runtimes |
| \`codesandbox\` | Container | ~2s | Web-dev workflows |
| \`replit\` | Container | ~3s | Long-running educational use |

Tier gating: \`capabilities.network: true\` flips \`sandbox_exec\` from
tier-2 to **tier-4**, requiring master approval. Policy engine
(ADR-0007) computes effective tier per-call.

Wires explicitly with \`panic-attack-mcp\` (pre-flight static analysis)
+ \`vordr-mcp\` (post-flight integrity). Three-cartridge **canonical
untrusted-execution flow**.

## ADR-0010 — Cross-machine coord federation

Promote \`local-coord-mcp\` from loopback-only to federated. Three
pillars:

1. **DID identity** — \`did:boj:peer:<base32-ML-DSA-public-key>\`;
private keys never leave the machine
2. **ML-KEM-1024 key exchange + AEAD** — post-quantum on the wire;
aligns EXHIBIT-B end-to-end
3. **Federated quarantine** — master visibility across machines;
master-uniqueness invariant federated via HOTSTUFF-style election

Three topology variants: mesh / hub / **hub-and-rim** (recommended for
production — dedicated routing machine keeps the federation up when any
LLM-peer machine goes down).

Opt-in per machine via \`COORD_FEDERATED=true\` + signed roster. **No
insecure-federation mode** — federation without crypto is not
federation.

Implementation plan is six staged sub-RFCs (~6 weeks total) so the
campaign can be reviewed in chunks rather than as a single mega-PR.

## Why this pair

Sandbox is the *biggest* execution-blast-radius operation BoJ exposes;
federation is the *most architecturally far-reaching* extension. Both
depend on ADR-0007 (policy DSL) landing first. Both touch the trust-tier
model from different angles — execution and identity. Coupling them in
one review surfaces the interactions early.

## Review focus

Recommend reading **Open questions** in both:

- ADR-0009: default provider choice (\`local\` vs \`e2b\`); GPU support;
output streaming protocol
- ADR-0010: DID method registration with W3C; roster mutability;
split-brain handling on partition heal; performance ceiling

The federation RFC is the largest commitment in epic #87 — call out
anything in the staged plan that feels off-sequence.

## What this doesn't change

- No code touched.
- No existing cartridges affected.
- ADR-0002 (BoJ-only MCP) stands; federation is *in-cartridge*, not
*between-MCPs*.

## Sequencing

Per epic #87: this is Tier B step 2 of 3. The third pair (items 5 + 6:
webhooks + sampling) follows. All three pairs are independent of each
other and of the code PRs (#88/#89/#91).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request May 20, 2026
## Summary

Closes the second Tier A item of epic #87. Every \`tools/call\` now
emits an OTLP/JSON span to the user's collector (Tempo, Jaeger,
Honeycomb, Grafana Agent, OTel Collector). Pairs naturally with the
\`observe-mcp\` / \`grafana-mcp\` / \`prometheus-mcp\` cartridges — one
telemetry destination, one pane.

## Why hand-rolled (no \`@opentelemetry/api\`)

The bridge has **zero runtime deps by policy** (package.json +
CLAUDE.md). Adding ~30 transitive packages for what is structurally a
few JSON-RPC wrappers isn't proportionate. OTLP/HTTP+JSON is a stable
wire spec; any conformant collector accepts these payloads. ~200 LOC vs
~30 npm packages.

## Off by default

Enabled only when \`OTEL_EXPORTER_OTLP_ENDPOINT\` is set.
\`startSpan()\` returns \`null\` when disabled; \`endSpan(null)\` is a
guarded no-op. **Zero runtime cost when unused.**

## Env vars (declared in \`glama.json\`)

| Var | Default | Purpose |
|---|---|---|
| \`OTEL_EXPORTER_OTLP_ENDPOINT\` | _unset → off_ | OTLP/HTTP collector
URL (e.g. \`http://localhost:4318\`) |
| \`OTEL_SERVICE_NAME\` | \`boj-server\` | Resource attribute on every
span |
| \`OTEL_SERVICE_VERSION\` | \`0.4.7\` | Resource attribute |
| \`OTEL_BATCH_MS\` | \`5000\` | Span-batch flush interval |
| \`OTEL_EXPORTER_OTLP_HEADERS\` | _unset_ | CSV \`key=value,…\` for
auth/tenant headers (e.g. Honeycomb) |

## Instrumentation

- **\`tools/call\`** → span \`mcp.tools.call\` with attributes:
  - \`mcp.tool.name\` (string)
  - \`mcp.tool.arg_count\` (int)
- **Status codes** (OTLP \`status.code\`):
  - \`1\` (OK) on successful dispatch
  - \`2\` (ERROR) on tool failure, with sanitized error message
- \`2\` (ERROR) on hardening-gate rejection, with \`mcp.rejection.code\`
attribute so dashboards can split by reason

Future PRs can wrap \`resources/read\` and \`prompts/get\` once #89
lands.

## Batching + shutdown safety

- 5s default flush interval (overridable)
- Hooks on \`beforeExit\`, \`SIGTERM\`, \`SIGINT\` force a final flush
- Bounded re-buffer on transport failure (cap 10k spans to avoid
runaway)
- \`setInterval\` is \`unref()\`'d so it doesn't keep the process alive
after stdin closes

## Tests

- **Disabled-mode**: \`isEnabled() === false\`; \`startSpan\` returns
\`null\`; \`endSpan(null)\` is safe; \`flush()\` is no-op
- **Enabled-mode**: \`traceId\` matches \`/^[0-9a-f]{32}$/\`; \`spanId\`
matches \`/^[0-9a-f]{16}$/\`; \`startNs\` is digit string
- 13/13 tests pass (11 existing + 2 new)
- End-to-end smoke: \`tools/call boj_health\` succeeds with no
\`OTEL_*\` env set; no behavior change observable from the MCP client

## What this enables

- Per-tool latency histograms in Grafana via OTLP → Tempo
- Cardinality-controlled tool-call counts in Prometheus (via collector
translation)
- Trace-driven debugging when a multi-cartridge composition (e.g.
\`audit-repo\` prompt from #89) goes wrong — every step is a span on the
same trace

## Sequencing

Independent of #88 (publish workflow) and #89 (resources/prompts). Can
land in any order.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <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