Security

Only what the code enforces

Every claim on this page names the line that backs it. CODED means the check is in the code on the call path. ENFORCED means a test, a database grant or a database policy makes a violation fail. Nothing here is a plan.

11 claims, 44 cited lines.

01

Tenant isolation by workspace

A workspace is one isolated tenant. The workspace comes from the authenticated key, never from the request body, the path or a header. A call that names another workspace is refused before that workspace is read.

  • CODED

    A scope that names another workspace is refused with WORKSPACE_REFUSED.

    src/ticket16/dispatch.mjs:140

  • CODED

    A payload that names another workspace is refused.

    src/ticket16/dispatch.mjs:171

  • CODED

    A key for an unserved workspace fails authentication before capability lookup.

    src/ticket16/dispatch.mjs:130

  • CODED

    One authorization function denies every cross-workspace call except a portfolio read.

    src/contracts/authorization.mjs:204

  • ENFORCED

    FORCE ROW LEVEL SECURITY on the record table, so the owner is not exempt.

    migrations/ticket9/0001_repository_records.sql:46

  • ENFORCED

    The policy matches the database role to one workspace id, on read and on write.

    migrations/ticket9/0001_repository_records.sql:75

02

Partner isolation

A partner reads and writes only its own rows. The database check covers writes as well as reads.

  • ENFORCED

    The partner policy is RESTRICTIVE and FOR ALL, so the workspace policy alone cannot satisfy it.

    migrations/ticket9/0001_repository_records.sql:108

  • CODED

    A partner scope comes from its partner grant and never from caller scope.

    src/ticket16/dispatch.mjs:154

  • CODED

    A partner call is refused by default when partner access is not composed.

    src/ticket16/dispatch.mjs:193

03

Append-only ledger and corrections

A ledger entry is never edited. A refund, a dispute or a manual correction appends a new entry that names the entry it corrects.

  • ENFORCED

    The application role holds SELECT, INSERT and UPDATE. It holds no DELETE.

    migrations/ticket9/0001_repository_records.sql:63

  • CODED

    A refund appends a refund-correction entry.

    src/ticket6/index.mjs:745

  • CODED

    A commission approval is immutable once it exists.

    src/ticket6/index.mjs:2035

  • CODED

    A reject is a separate append-only record. Nothing edits an approval or a reject.

    src/ticket6/index.mjs:2051

04

Read-only Stripe access

Parka makes one Stripe call, a read of the event list. Every other Stripe call is refused in code before the network is reached.

  • CODED

    The client allows only GET https://api.stripe.com/v1/events.

    src/runtime/stripe-client.mjs:32

  • CODED

    Any method other than GET is refused before fetch is reached.

    src/runtime/stripe-client.mjs:36

  • CODED

    A Stripe write is refused with STRIPE_WRITE_REFUSED.

    src/ticket10/index.mjs:161

  • ENFORCED

    Gate 14 pins the flags and surfaces of the Stripe capability.

    src/gate14/checker.mjs:38

05

Parka never moves money

Parka calculates what a partner is owed. You pay the partner with your own rails. A person records the receipt.

  • CODED

    There is no charge, transfer or payout call anywhere in the client.

    src/runtime/stripe-client.mjs:32

  • CODED

    Recording a payout takes an external reference and operator evidence for a payout that already happened.

    src/ticket7/index.mjs:292

  • ENFORCED

    Recording a payout receipt is pinned as a human gate.

    src/gate8/checker.mjs:46

06

API key hashing

Only a peppered hash of an API key is stored. The plaintext appears once, at mint, and never again.

  • CODED

    The stored hash is HMAC-SHA256 over the key with a runtime pepper.

    src/ticket16/keys.mjs:48

  • CODED

    Verification compares in constant time.

    src/ticket16/keys.mjs:74

  • CODED

    A revoked key fails closed.

    src/ticket16/dispatch.mjs:58

  • CODED

    Postgres stores a second digest over a database-local secret, so a copied hash is useless.

    migrations/ticket18/0002_db_key_digest.sql:105

07

Human gates

An agent cannot run a human gate. The call creates an approval request and runs nothing. Only a person approves it, and approval runs the stored call as that person.

  • CODED

    A capability is automation safe or it is a human gate. An incoherent pair is refused at declaration.

    src/contracts/manifest.mjs:67

  • CODED

    A human gate refuses every actor kind except human, and refuses the mcp surface.

    src/contracts/authorization.mjs:214

  • CODED

    A served key never carries human presence.

    src/ticket16/dispatch.mjs:144

  • CODED

    A human gate through the dispatcher creates an approval request. The implementation is not called.

    src/ticket16/dispatch.mjs:199

  • ENFORCED

    Gate 8 dispatches every included surface and asserts every human gate stays off MCP.

    tests/gate8.test.mjs:234

08

An agent can never widen its own rights

A credential change is a human gate. An agent cannot grant itself access, and it cannot approve its own request.

  • CODED

    Binding a partner key to a grant is declared a human gate.

    src/partner-access/service.mjs:30

  • CODED

    A grant takes its program, relationship and partner identity from the key record, never from the payload.

    src/partner-access/service.mjs:81

  • CODED

    Minting a key is declared a human gate. Revoking one stays automation safe.

    src/ticket16/index.mjs:134

  • CODED

    Approve and reject cannot be the target of an approval request.

    src/approvals/index.mjs:102

  • ENFORCED

    A partner key cannot grant access and cannot approve its own request.

    tests/k0-grant-access-human-gate.test.mjs:347

09

Audit trail

Every admitted or refused partner call appends one audit row. A row is never updated or deleted, and it never holds a full credential.

  • ENFORCED

    The application role is granted SELECT and INSERT only.

    migrations/partner-access/0003_partner_audit_log.sql:45

  • ENFORCED

    A row holds at most a 16 character credential prefix, and the check refuses the key prefix.

    migrations/partner-access/0003_partner_audit_log.sql:19

  • CODED

    The audit entry is written whether the call is admitted or refused, and it commits with the refusal.

    src/ticket16/dispatch.mjs:194

10

Secrets are not returned or logged

A runtime secret is not returned through a surface and not written to a log line.

  • CODED

    A secret is held in a wrapper. Only one method returns the value.

    src/runtime/config.mjs:12

  • CODED

    A redactor removes every configured secret from an output string.

    src/runtime/config.mjs:41

  • CODED

    The health body is redacted before it is sent.

    src/runtime/served.mjs:71

  • CODED

    A CLI refusal prints a code and no message, because a message can quote a connection string.

    src/ticket16/cli.mjs:34

11

One refusal name on every surface

The API, the CLI and MCP return the same refusal name for the same refusal, so one log search covers all three.

  • CODED

    One refusal-to-status map covers the served surface.

    src/ticket16/transport.mjs:46

  • CODED

    The MCP error carries the same code in the message and in the data.

    src/ticket16/transport.mjs:378

  • ENFORCED

    One wrong-workspace call returns the same name on the API, the CLI and MCP.

    tests/adr0005-f1-surface-parity.test.mjs:349

What this page does not claim

  • Parka holds no certification and no audit report. There is none to show.
  • There is no public runtime health endpoint, so this site publishes no uptime number and no status page.
  • Applying a migration to a real database is its own human gate in Parka. A claim about a database grant is a claim about the schema the migration declares.
  • The operator identity on a command-line gate is self asserted. Nothing verifies that a person is at the keyboard.
  • Nobody on the site team has watched a live Parka runtime, so no claim here is an observation.

Reporting something

Mail us if you find a problem. Tell us what you did and what you saw. We read every report and reply by email.

Partner programs on Stripe, run by agents. People approve the money.

Get started