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>
- .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>
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>
`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>
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 b87992f (the 2026-04-11 drift incident); the constant
mirrors what cli.js embeds for its OAuth token-refresh flow.
2. README.md API key example made clearly fake (ocp_example12345abcde...) to
avoid gitleaks false-positives and clarify to readers it is not real.
The ocp_ prefix IS the real prefix (keys.mjs line 80: randomBytes(24).base64url),
so the prior example could be mistaken for a real truncated key.
3. PR template: added Privacy self-check section for PUBLIC repos below the
existing 5.3 user-visible change self-check section.
4. .gitleaks.toml: new file with allowlist for the three confirmed non-issues
(OAUTH_CLIENT_ID constant, README placeholder regex, old plan doc path).
No code or behavior change beyond the docs, README, and new config file.
Closes part of ocp#44.
Co-authored-by: Tao Deng <dtzp555@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
* 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 b87992f on 2026-04-11 (the fabricated
"/api/oauth/usage" endpoint, which does not appear in cli.js and broke
the dashboard usage bar for nine days).
This PR is governance-only. It does not modify server.mjs, package.json,
or any runtime code. It is intentionally shipped as one reviewable unit
per Iron Rule 11 (governance is one layer).
Files added:
- ALIGNMENT.md
Supreme scope document. Core principle: OCP is a proxy layer for
Claude Code, not an extension layer. Five binding Rules: grep
cli.js first; no invention; match the implementation; unalignable
features are deleted; commits cite cli.js line numbers. Includes
the 2026-04-11 drift postmortem, the Unalignable Policy, and an
Annual Alignment Audit fixed to 11 April each year.
- CLAUDE.md
Project session instructions. Flags ALIGNMENT.md as required
reading before any code. Codifies three hard requirements for
server.mjs changes: cli.js citation, CI blacklist pass, and an
independent reviewer per Iron Rule 10. References CC 开发铁律
Rules 10, 11, and 12.
- .github/PULL_REQUEST_TEMPLATE.md
Mandatory "Claude Code Alignment Evidence" section. Three author
checkboxes (cli.js citation, scope justification if cli.js does
not perform the op, commit-message citations). Reviewer checklist
requires opening cli.js at the cited lines before approval. A PR
with this section blank receives request-changes.
- .github/workflows/alignment.yml
Hard-fail blacklist on server.mjs for tokens "api/oauth/usage"
and "api/usage" (scan restricted to server.mjs; ALIGNMENT.md and
CLAUDE.md may quote them as historical references). Soft check
over all PR commit messages for "Claude Code uses X" / "cli.js
uses X" assertions lacking a cli.js:NNNN or cli.js vE4 <fn>
citation.
Historical reference: b87992f ("fix: use dedicated /api/oauth/usage
endpoint for reliable plan data") asserted the endpoint was used by
Claude Code CLI. The string does not occur in cli.js. Root cause was
LLM hallucination accepted without grep verification. See ALIGNMENT.md
-> Historical Lesson for the full record.
Merge precondition: this PR must be approved by an independent reviewer
(Iron Rule 10). The drafter of this commit may not self-approve.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(alignment): pin first audit to 2026-04-20 (cli.js 2.1.89, SHA-256 a9950ef6)
First annual alignment audit pin. Records the cli.js version and content
hash that the current ALIGNMENT.md codified implementations mirror.
- Claude Code version: 2.1.89
- cli.js SHA-256: a9950ef6407fdc750bddb673852485500387e524a99d42385cb81e7d17128e01
- Audit date: 2026-04-20
- Auditor: Tao Deng
Next audit: 2027-04-11 (drift anniversary).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci(alignment): narrow blacklist to full host+path + strip comments before grep
Two false positives discovered during PR #20 bootstrap CI:
1. /api/usage is a legitimate OCP dashboard route (per-key quota, added
in v3.8, server.mjs:1472). The bare token "api/usage" was too broad.
2. The ANCHOR warning comment in server.mjs (added by PR #21) references
/api/oauth/usage as a DO-NOT-USE example, triggering the scanner.
Fix: require full host "api.anthropic.com/api/oauth/usage" to ensure
only real outbound fetch calls trip the guard, and strip line comments
with sed before grep so historical ANCHOR warnings pass.
Amendment procedure (ALIGNMENT.md) still governs future blacklist
changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Oracle Public Cloud User <opc@instance-20230820-1333.subnet07301351.vcn07301351.oraclevcn.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>