ci(fork): add pytest-run job with Postgres service container#2
Closed
HaraldeRoessler wants to merge 3 commits into
Closed
ci(fork): add pytest-run job with Postgres service container#2HaraldeRoessler wants to merge 3 commits into
HaraldeRoessler wants to merge 3 commits into
Conversation
Previously the fork CI only ran pytest --collect-only, never executing any tests. This meant regressions like the PR#17 credit-middleware 402-block loss were invisible to CI — the concurrency test (test_concurrent_deducts_respect_balance) would have caught it immediately, but it never ran. New job: - pytest-run: spins up a Postgres 16 service container, runs init_db.sql for the schema, executes tests/test_credit_middleware.py with proper env vars (CREDITS_ENABLED=true, MOLTSTACK_DB_PW, etc.) This is intentionally scoped to credit middleware tests only — the test_caep.py and protocol compliance tests need additional infrastructure (sandbox, admin keys) and can be added separately. Also adds httpx to the collect job's pip install (needed for import to succeed).
Owner
Author
|
Superseded — CI changes moved to PR#58 (MoltyCel#58) |
HaraldeRoessler
pushed a commit
that referenced
this pull request
Jul 3, 2026
…iew fixes Erstes §12-Review (run 2026-05-28, label openclaw-plugin-v2.0.0-alpha.0) fand 6 Blocker. Dieser PR adressiert 5 davon im Code + 1 als ADR-deferral. Code-Fixes: - #1 Fail-Open Default → Neuer Config-Param `failOpen` (default false). before_tool_call + inbound_claim blocken jetzt bei API-Lookup- Fehlern, statt durchzulassen. Opt-in via failOpen=true. - #2 inbound_claim DENY-Ignorierung → Review-Befund war überwiegend Halluzination (Score-Check existierte schon), aber der Fail-Open- Pfad ist via #1 jetzt auch hier fail-closed. - MoltyCel#4 Cache TTL Default 300s → 10s (Zero-Trust Revocation-Latency). - MoltyCel#5 Vendored OpenClaw-Types ohne Versions-Anchor → Header-Kommentar in openclaw-types.ts pinnt jetzt explizit Range 0.9.x – 1.0.x + Anweisung „minor bump on upstream-breaking change". README zeigt Range in Architektur-Section. - MoltyCel#6 GDPR/Privacy → Neue README-Section „Privacy & Data Handling" listet explizit alle Endpoints, gesendete Datenfelder, Endpoint- URL, Retention-Pointer, Disable-Mechanismus. ADR-Deferral: - MoltyCel#3 JWS Response-Signatur-Verifikation → ADR 0001 (docs/decisions/) erklärt warum v2.1 statt v2.0.0-alpha.1: braucht Bootstrap-/ Rotations-/Failure-Mode-Design, eigener Sprint. Risiko- Mitigation in v2.0.0-alpha.1 durch #1 (kein Fall-Through bei API-unreachable). README-Section „Security Posture & Roadmap" kommuniziert v2.1-Plan + verbleibende MITM-Surface. Publish-Prep (re-applied, since v2.0.0-alpha.0 origin/main state hat diese noch nicht): - Paketname @moltrust/openclaw → @moltrust/openclaw-plugin - prepublishOnly, engines (node>=20), publishConfig.access: public - author, bugs, repository.url (Standardformat) - .gitignore + .npmignore Tests: 27 → 31 (4 neue, fail-closed + opt-in-fail-open je hook). py-equivalent: tsc + vitest grün, package size ~12 kB. Re-§12-Review läuft nach Merge gegen das gleiche Briefing.
HaraldeRoessler
pushed a commit
that referenced
this pull request
Jul 3, 2026
Re-§12-Review für alpha.1 (run 2026-05-28 17:27 UTC, output ~/moltstack/reviews/20260528_172832_openclaw-plugin-v2.0.0-alpha.1_review.md) votierte ÜBERARBEITEN. Drei neue Blocker für alpha.2 — alle in diesem Commit adressiert. Blocker #1 (Test-Lücke): kombinatorischer Pfad "own DID OK + counterparty lookup fail + failOpen=true → ALLOW" war nicht getestet. Test ergänzt in before-tool-call.test.ts. Blocker #2 (Performance): sequenzielle Counterparty-Lookups in before-tool-call.ts waren O(N × API-latency) — 4 DIDs × 50ms = 200ms+ Event-Loop-Block. Fix: Promise.allSettled + post-evaluation. Block- Priority ist deterministisch (erste Counterparty im array order wins). Own-DID-Check bleibt VOR counterparties (early-exit bei eigener Insufficienz). Blocker MoltyCel#3 (Air-Gap Lücke): die moltrust_verify / moltrust_trust_score / moltrust_endorse Agent-Tools blieben auch bei minTrustScore=0 + verifyOnStart=false beim Agent-Runtime registriert — LLM-Halluzinationen konnten ungewollte DID-Lookups triggern. Neue Config-Option `registerMoltrustTools` (default true). Wenn false: die 3 registerTool- Calls werden geskipped, Tools sind für die LLM nicht aufrufbar. Slash- Commands + RPC + Lifecycle-Hooks bleiben unverändert (explizite Operator/User-Aktionen, nicht LLM-aufrufbar). README: Privacy-Section schärft Disable-Anweisung — "Disabling automatic outbound calls" (alt) vs neue "True air-gap mode" mit registerMoltrustTools=false. Configuration-Beispiel zeigt neuen Default-Wert. Tests: 31 → 32 (1 neuer für kombinatorischen Pfad). Alle 32 grün, tsc grün. Re-Re-§12-Review läuft mit alpha.2-Briefing-Append vor npm publish.
HaraldeRoessler
pushed a commit
that referenced
this pull request
Jul 3, 2026
…ltyCel#128) * docs(specs): D-1 Acceptance-Gate architecture brief (design-only) Scope: AAE draft-04 §5 Step 1 (signature verify + signing-authority) + Step 2 (payload/schema/cty). Decisions: #1 JWS-wrapped VC submit-contract (extract blocks from verified payload; component-1 API/raw_canonical impact named); #2 did:web + did:moltrust launch (did:key follow-on); MoltyCel#3 resolve-and-verify with trust-tiering (trusted vs unverified_issuer, no hard-allowlist); MoltyCel#4 scope = steps 1+2 only (step 4 subject-binding + step 9 delegation = follow-ons). PyJWT 2.12.1 (no new dep). Canonicalization clarity: D-1 verifies JOSE-JWS bytes, not JCS raw_canonical. Open sign-off: DID-resolution depth/SSRF/caching, raw_canonical redefinition, trust-tier persistence. * docs(specs): resolve 4 D-1 sign-off points (design-only) 1) DID-resolution SSRF/DoS = same egress-proxy as revocation_check (no new mitigation); did:web gated on proxy, D-1 LAUNCHES did:moltrust-only (no outbound, not proxy-gated). 2) raw_canonical = JWS-payload (trigger structurally unchanged); breaking submit-contract change, only smoke-rows affected. 3) trust-tier = new additive column issuer_trust_tier (trusted/unverified_issuer, analog value_source). 4) did:web VM-dereferencing = new layer (resolver gives raw DID-doc only). Phased launch: A did:moltrust-only now, B did:web when egress-proxy live. * docs(specs): D-1 review-hardening — 4 criticals + 2 mediums resolved (design-only) alg-confusion (explicit algorithms=[EdDSA] allowlist, never trust header alg); kid strict DID-URL validation + path-traversal/look-alike protection; canonicalization = exact b64url-decoded payload bytes (never re-serialize); submit rate-limit + per-issuer quota (PK already blocks exact replays); did:moltrust registry SPOF -> key rotation; JSON duplicate-keys reject via object_pairs_hook. Implementation contract, not architecture change. --------- Co-authored-by: Lars Kroehl <kersten.kroehl@cryptokri.ch>
HaraldeRoessler
added a commit
that referenced
this pull request
Jul 3, 2026
The 3-model review blocker #1 (downgrade/stripping) was not fully solved by AND-logic alone: my first implementation stripped the proof field before signing, so an attacker who removed the Dilithium leg left the Ed25519 signature valid over unchanged bytes — the exact OR-downgrade the review flagged. A prior test even asserted the wrong behaviour (stripped single verifies standalone). Fix per the review explicit requirement (proof field must be included in the signed message): - dual_sign now builds a proof SKELETON (every intended proof dict with proofValue blanked) and signs the credential body PLUS that skeleton. Both Ed25519 and Dilithium sign the same canonicalized skeleton bytes. - verify_proof reconstructs the same skeleton from the presented proofs. If a leg is missing, the skeleton differs from what the issuer signed, so the surviving Ed25519 signature fails too. Stripping a leg now breaks every remaining signature — composite-signature semantics (IETF composite-sigs, BSI TR-02102-1). - dual_sign refuses to silently fall back to Ed25519-only when Dilithium is configured but signing fails (that would re-open the downgrade path: an attacker cannot distinguish a deliberate Ed25519-only cred from a failed-dual one). It raises instead. - Legacy sort_keys credentials (no canonicalizationAlgorithm) still verify over the body only — backward compat unchanged, and they only ever had one leg so there was nothing to strip. Also fix blocker #2 fully: scripts/generate_dilithium_keys.py --kms mode previously printed base64(secret_key) to stdout. It now writes the KMS-ready base64 to a chmod 600 file (dilithium_secret_key.kms.b64) instead. Runtime proof: script stdout contains only the PUBLIC key; no secret (hex or base64) reaches stdout/stderr. Secret files are mode 0600. Verified: - Downgrade attack (PQC-enabled issuer -> strip Dilithium -> verify) now FAILS: Ed25519 signature invalid because skeleton changed. - Legit Ed25519-only (non-PQC issuer) still verifies. - Legacy sort_keys credentials still verify. - Dual both-legs-valid -> valid; one bad leg -> whole cred invalid. - JCS fail-closed raises when jcs missing. - py_compile clean on all 8 files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The fork CI previously only ran
pytest --collect-only— tests were never executed. This meant regressions like the PR#17 credit-middleware 402-block loss were invisible to CI.The concurrency test
test_concurrent_deducts_respect_balancewould have caught it immediately (expects 3×200 + 7×402, got 10×200) — but it never ran.What's added
pytest-runjob — spins up a Postgres 16 service container, runsinit_db.sqlfor the schema, then executestests/test_credit_middleware.pywith proper env vars:Scoped to credit middleware tests for now. Other test files (test_caep.py, test_protocol_compliance.py) need additional infrastructure and can follow separately.
Also adds
httpxto pip install in the collect job (needed for imports to succeed).Why this matters
The entire PR#17 regression was discovered by Kersten running tests manually on the production server. With this CI job, the red test blocks the merge automatically.