mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-27 16:05:07 +00:00
e08cb94faf91e4307e1f57b6acf6f357d8fbde35
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a99395ed0c |
ci: fix release.yml's no-CHANGELOG path, which would have failed the release job (#202) (#206)
* ci: cover models.json in the alignment guardrail; fix release.yml's no-CHANGELOG path Two CI-layer fixes found during the v3.25.0 review. Same layer, both small, so they land together (Iron Rule 11). #198 — alignment.yml did not run on a models.json-only PR. The `paths:` filter listed server.mjs / setup.mjs / scripts / lib / ocp / ocp-connect, but not models.json. That made CLAUDE.md hard-requirement #2 ("CI blacklist pass") vacuous for exactly the PRs that change model routing: confirmed on #192, where only gitleaks and test-features ran. models.json is not inert data. It drives MODEL_MAP and VALID_MODELS, the default request model, and — since ADR 0009 — the global MAX_PROMPT_CHARS truncation budget. A models.json-only PR can therefore change server.mjs's runtime behavior with the guardrail never running. models.schema.json is included for the same reason one level up: loosening the schema is what would let a malformed models.json through. Adding paths only widens coverage; the blacklist grep still scans server.mjs, so this costs nothing and closes the gap. Per CLAUDE.md this is a PR amendment to alignment.yml, which is the sanctioned way to change it (removing entries would need an ALIGNMENT.md amendment; nothing is removed here). #202 — release.yml's no-CHANGELOG fallback would have failed the release job. The branch wrote an output named `notes` and exited WITHOUT creating /tmp/release-notes.md, while the create step hard-codes `--notes-file /tmp/release-notes.md`. So the one path that exists to "degrade to minimal notes" instead produced a failed release. Verified both directions by extracting the step's actual script from the YAML and running it, rather than reading it: PRE-FIX, no CHANGELOG -> exit 0, GITHUB_OUTPUT="notes=Release v3.25.0", /tmp/release-notes.md MISSING -> gh release create --notes-file WOULD FAIL POST-FIX, no CHANGELOG -> exit 0, notes_file set, file present ("Release v3.25.0") POST-FIX, with CHANGELOG -> file present, first line "## v3.25.0 — 2026-07-27" Fixed by writing the file in that branch, and by removing the hard-coded-path coupling entirely: both branches now set `notes_file` and the create step consumes `steps.notes.outputs.notes_file`. That output existed already and was never read — the two only agreed by accident. Also added `set -euo pipefail` (the step previously ran unset-tolerant) and an echo of the resolved notes before creating the release, so a wrong-looking body is visible in the job log instead of only on the published release. NOT changed: the empty-extraction guard. My issue text suggested adding one, but `if [ ! -s "$NOTES" ]` was already there and already handles a heading mismatch. Correcting that claim on #202 rather than taking credit for it. Both workflows re-validated as YAML. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8 * ci: drop the alignment.yml paths change — it would have been a green check for a check that never ran Reverting my own half of this PR. The reviewer proved the alignment.yml change was theatre, and my issue #198 was filed on a wrong premise. What I verified myself before reverting: - the alignment job BODY references models.json zero times; only the paths filter I added mentioned it - test.yml is `pull_request:` with NO paths filter, so it already runs on every PR, models.json-only ones included - on a deliberately corrupted models.json (contextWindow 1000000, a typo'd openclawName), `npm test` catches it: 455 passed, 2 failed So the real guard on models.json already existed and always ran. Adding the path would only have made a job execute that inspects nothing about models.json, and then reported a green "Alignment Guardrail" — implying a check that did not happen. That is strictly worse than the job not running, which is precisely the reviewer's point. #198's premise was also wrong. The blacklist greps server.mjs for known hallucinated tokens. A models.json-only PR cannot introduce a token into server.mjs, so CLAUDE.md hard-requirement #2 is INAPPLICABLE on such a PR, not vacuous. I read "the guardrail didn't run" as "coverage gap" without checking what the guardrail actually inspects. The release.yml half is unaffected and stays: that one is a real, reproduced failure (the no-CHANGELOG branch never wrote the file the create step consumes). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017gbqUZ8HfBZpjjbzQ85oH8 --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6dff36959a |
chore(governance): pin legacy OAuth host in alignment.yml + ALIGNMENT.md amendment (#123) (#128)
Follow-up to the 2026-05-31 audit (deferred from #112). The OAuth token host platform.claude.com/v1/oauth/token was verified against the compiled cli.js in #119; this pins the legacy WRONG host so a future accidental revert hard-fails CI. - .github/workflows/alignment.yml: add "console.anthropic.com/v1/oauth/token" to the BLACKLIST; rewrite the comment + failure message so the blacklist now documents TWO kinds of token — known hallucinations AND pinned wrong-host variants of a verified Class A endpoint (a hit means a drift, not necessarily a hallucination). The pinned token is absent from server.mjs (which uses platform.claude.com), so CI stays green. - ALIGNMENT.md: new "OAuth token-host verification (2026-05-31)" subsection recording the binary verification (claude.exe 2.1.154, strings, no live probe) and the dual-purpose blacklist policy. Purely additive; Rules / audit pin / Historical Lesson untouched. Per ALIGNMENT.md Amendment Procedure: (a) motivating evidence cited (issues #112/#119/#123), (b) independent fresh-context opus reviewer APPROVE — verified the pinned token does not trip the build (absent from server.mjs; live host not blacklisted), YAML valid, amendment consistent with the server.mjs verification comment, purely additive scope. (c) not incident-driven (a confirming verification, not a new drift) so Historical Lesson unchanged. Closes #123. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
1dd6fb9440 |
docs(governance): add ADR 0006 OpenAI shim scope + Class A/B taxonomy (#100)
Introduces an explicit two-class taxonomy of OCP endpoints to resolve the structural ambiguity surfaced by PR #99 (external response_format honoring on /v1/chat/completions): - Class A: cli.js-mirror endpoints. Rules 1-5 of ALIGNMENT.md apply verbatim. Citation requirement unchanged (cli.js:NNNN). The 2026-04-11 drift discipline is preserved without weakening. - Class B: OCP-owned compatibility endpoints. Anchored to OpenAI's /v1/chat/completions specification (B.1) or to an authorizing ADR (B.2). Citation shifts to spec section + ADR number. Class B inherits the same anti-invention discipline; the anchor differs. Grandfather provision in ADR 0006 retroactively authorizes the 12 existing B.2 administrative endpoints at v3.16.4 behaviour (one-time, contract-frozen). New B.2 endpoints or any new method on a grandfathered endpoint requires its own ADR per Rule 4 (Class B mapping). Changes: - new: docs/adr/0006-openai-shim-scope.md - new: docs/openai-compat-pin.md (placeholder for first B.1 audit) - mod: ALIGNMENT.md (Class B section, rule mapping table, updated Unalignable Policy and Annual Audit scope; Rules 1-5 byte-identical) - mod: .github/PULL_REQUEST_TEMPLATE.md (Endpoint Class radio, separate evidence sections for A vs B, reviewer checklist updated) - mod: docs/adr/README.md (index entry for ADR 0006) Independent reviewer (fresh-context opus per Iron Rule 10) verified: all 12 load-bearing checks pass — Rules 1-5 byte-identical to origin/main, 2026-04-11 drift narrative unchanged, explicit non-relitigation safeguard present in ADR 0006, grandfather provision narrowly scoped, Class B inventory matches server.mjs reality (14/14), single governance layer per Iron Rule 11 (no server.mjs touch), alignment.yml unmodified. Verdict: APPROVE_WITH_MINOR with 3 of 5 non-blocking suggestions folded in (operations-vs-endpoints precision, PR template Hybrid wording, openai-compat-pin.md stub). Triggering incident: PR #99 by external contributor (response_format honoring on /v1/chat/completions). This governance PR ships separately per Iron Rule 11 (IDR); the feature PR #99 will rebase on this and declare Class B with ADR 0006 citation. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
9e25160527 |
refactor: hoist port literal to lib/constants.mjs + CI gate (v3.16.4) (#98)
Closes the structural side of the port-drift cascade addressed by
v3.16.2/v3.16.3. Those releases reverted the literal line-by-line; this
one removes the invitation to drift.
Changes:
* NEW lib/constants.mjs — exports DEFAULT_PORT=3456, LOCAL_HOST,
OPENAI_API_BASE, LOCAL_PROXY_URL.
* server.mjs / setup.mjs / scripts/upgrade.mjs / scripts/doctor.mjs
(x2) / scripts/sync-openclaw.mjs all import DEFAULT_PORT from
lib/constants.mjs instead of hardcoding "3456".
* .github/workflows/alignment.yml:
- path filter extended to setup.mjs, scripts/**, lib/**,
ocp, ocp-connect.
- NEW job port-spot hard-fails any PR that introduces a hardcoded
"3478" or "3456" literal outside EXEMPT_REGEX (lib/constants.mjs,
test-features.mjs, ocp/ocp-connect bash CLIs, docs, the workflow
itself).
* Doc-comment rewording so CI grep finds zero hits.
No behavior change for any user. CLAUDE_PROXY_PORT env var still wins
at runtime; only the unset-env fallback now flows through one constant.
ALIGNMENT.md note: server.mjs change is one import + one literal swap,
mechanical. No cli.js operation changed; the citation requirement does
not apply.
cli.js: not applicable — mechanical refactor, no behavior change.
Co-authored-by: dtzp555 <dtzp555@gmail.com>
|
||
|
|
342a0a44f5 |
docs(funding): add Buy Me a Coffee link + GitHub FUNDING.yml (#68)
- .github/FUNDING.yml — enables GitHub's native "Sponsor" button on the repo page, pointing to buymeacoffee.com/dtzp555. Other platforms (GitHub Sponsors, Ko-fi) are commented out and can be enabled later by uncommenting + filling in handles. - README.md § Support OCP — new section just before License. States the free-and-open-source commitment, lists the kinds of work that don't show up in commits (multi-machine debugging, IDE validation, drift incidents, concurrency leaks), and offers a single ☕ link for users who want to support continued maintenance. Explicitly disclaims paid tiers / premium features so the open-source posture stays unambiguous. server.mjs is not modified; this commit is doc-only and therefore exempt from the cli.js citation requirement (ALIGNMENT.md Rule 5 applies only to commits that touch server.mjs). Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
c998d21a4f |
chore(ci): add gitleaks workflow to scan PRs and pushes to main (#64)
The repo has shipped `.gitleaks.toml` (with project-specific allowlist entries — public OAuth client ID, README placeholders, an old plan doc) since the privacy remediation work, but no GitHub Action invoked it. The config was orphan: real protection only when someone ran gitleaks locally, never gating merges. This workflow wires `.gitleaks.toml` into CI: - Triggers on every `pull_request` (any branch) and `push` to `main`. - Uses `gitleaks/gitleaks-action@v2`, which auto-detects the repo-root `.gitleaks.toml` and applies its allowlist. - Hard-fails on any leak. No `continue-on-error`. Public repo policy. - `permissions: contents: read` — minimum required scope. - `fetch-depth: 0` so the action can scan full history (the action's default behavior; explicit here for clarity). Verification path: - The workflow runs on this PR itself; if any secret were ever committed to the repo, the scan fails here. Prior audit confirmed the tracked tree is clean of real secrets, so this PR's own scan should pass. Refs: audit side-finding 4 of 4. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
0752f666fb |
test: wire test-features.mjs to npm test + add minimal CI smoke workflow (#60)
`test-features.mjs` shipped at v3.8.0 (per CHANGELOG of the keys.mjs quota+cache work) and is referenced from AGENTS.md as the project's only test artifact, but until now nothing actually ran it — no `npm test` script, no CI step. Wiring it up so it runs on every push and PR. ### Changes - `package.json`: add `"test": "node test-features.mjs"` to scripts. - `.github/workflows/test.yml` (new): single-job workflow that runs `npm test` on push to main and on every PR. Uses Node 24 because `keys.mjs` imports `node:sqlite`, which is stable in Node 23+ (Node 24 is the current LTS; Node 22 would need `--experimental-sqlite`). No `npm install` step — OCP has zero external runtime dependencies per `package-lock.json`. - `AGENTS.md`: note that `test-features.mjs` runs via `npm test` and is enforced by `.github/workflows/test.yml`. ### Why this is a hard check, not a soft check `test-features.mjs` is self-contained — it imports `keys.mjs` and exercises the SQLite-backed key/quota/cache code paths against a throwaway test DB at `~/.ocp/ocp-test.db`. It does NOT require: - a live claude CLI binary - a running OCP server - any network access So CI can run it as a real check; no `continue-on-error` needed. ### Local verification ``` $ npm test [...] === Results: 24 passed, 0 failed === ``` 24 assertions cover createKey / listKeys / quota math / cache hash determinism / cache TTL / clearCache. Exit code is 1 on any failure (`process.exit(failed > 0 ? 1 : 0)` at the bottom of test-features.mjs). ### Future expansion If the suite later grows to include tests that DO require a live claude CLI or a running OCP, mark those steps `continue-on-error: true` (or split them into a separate job). The comment in `test.yml` documents this contract. Refs: audit (test-features.mjs orphan / unrunnable in CI). Co-authored-by: dtzp555 <dtzp555@gmail.com> |
||
|
|
cff06439fa |
chore(privacy): remediation follow-up from ocp#44 (#45)
Three-part follow-up from the 2026-04-22 privacy postmortem:
1. OAUTH_CLIENT_ID verified as public Claude Code constant (not a secret).
Added gitleaks allowlist entry. The value 9d1c250a-e61b-44d9-88ed-5944d1962f5e
is the public PKCE client ID used by the Claude Code CLI — public clients in
PKCE flows have no client secret, so the ID itself carries no secret value.
Introduced in commit
|
||
|
|
497ff1dcd2 |
chore(governance): add release-kit overlay + PR self-check + auto-release workflow (#35)
Implements cc-rules v1.4's 第五律 5.5 project overlay requirement. - CLAUDE.md: declare release_kit: YAML block (version_source, changelog, release_channel, docs_source, resource_lists, new_feature_doc_expectations, bootstrap_quirk_policy) - .github/PULL_REQUEST_TEMPLATE.md: add 5.3 user-visible-change self-check section with reviewer gate instruction - .github/workflows/release.yml (NEW): auto-create GitHub Release from CHANGELOG.md section on v* tag push. Idempotent (checks if release already exists). Closes the gap that caused v3.9.0 / v3.10.0 / v3.11.0 to each miss their GH Release. Governance-only change. No code, no user-visible behavior change (the workflow only fires on future tags). No README update needed. Co-authored-by: Tao Deng <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
2853088261 |
[Constitution] Alignment principle + CI guardrails (addresses b87992f drift) (#20)
* docs(constitution): establish OCP alignment constitution + CI guardrails (PR A) Introduces the OCP project constitution to structurally prevent the kind of scope drift that produced commit |