Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,29 @@ jobs:
- name: Build all packages
run: pnpm -w build

- name: Test core crypto functions
- name: Test @peac/crypto sign/verify runtime smoke
run: |
echo "Testing @peac/core crypto functions with Node.js..."
echo "Testing @peac/crypto sign/verify round-trip with Node.js..."

node --input-type=module -e "
const m = await import('./packages/core/dist/index.js');
const { signDetached, verifyDetached, generateEdDSAKeyPair, validateKidFormat } = m;
const m = await import('./packages/crypto/dist/index.mjs');
const { sign, verify, generateKeypair } = m;
console.log('Testing with Node.js...');
const { privateKey, publicKey, kid } = await generateEdDSAKeyPair();
const { privateKey, publicKey } = await generateKeypair();
console.log('[OK] Key generation works');

if (!validateKidFormat(kid)) throw new Error('Generated kid invalid format');
console.log('[OK] Kid validation works');

const payload = 'test payload';
const jws = await signDetached(payload, privateKey, kid);
const kid = 'nightly-test-key';
const payload = { msg: 'test payload' };
const jws = await sign(payload, privateKey, kid);
if (typeof jws !== 'string' || jws.split('.').length !== 3) {
throw new Error('sign() did not produce a compact JWS');
}
console.log('[OK] Signing works');

const verified = await verifyDetached(payload, jws, publicKey);
if (!verified) throw new Error('Verification failed');
const result = await verify(jws, publicKey);
if (!result || !result.payload || result.payload.msg !== payload.msg) {
throw new Error('Verification did not return the original payload');
}
console.log('[OK] Verification works');
console.log('[OK] Node.js runtime validation complete');
"
Expand Down
12 changes: 9 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ The `PEAC-Receipt` header carries a compact JWS (never a bare `receipt_ref`).

For A2A (Agent-to-Agent Protocol, Linux Foundation) discovery via `/.well-known/agent-card.json`:

**Agent Card (`capabilities.extensions[]` array, A2A v0.3.0 and v1.0.0):**
**Agent Card (`capabilities.extensions[]` array, A2A v1.0.0):**

```json
{
"name": "Example Agent",
"url": "https://agent.example",
"supportedInterfaces": [
{
"url": "https://agent.example",
"protocolBinding": "http+json",
"protocolVersion": "1.0.0"
}
],
"capabilities": {
"extensions": [
{
Expand Down Expand Up @@ -93,7 +99,7 @@ For A2A (Agent-to-Agent Protocol, Linux Foundation) discovery via `/.well-known/
}
```

The extension URI key maps to a nested object containing the carrier array. This follows the A2A metadata convention. Both v0.3.0 and v1.0.0 Agent Card shapes are accepted.
The extension URI key maps to a nested object containing the carrier array. This follows the A2A metadata convention. A2A v1.0.0 Agent Card shape is required; v0.3.0 compatibility was removed in v0.13.0 (DD-186). Cards without a valid `supportedInterfaces[0].url` are rejected.

## Discovery

Expand Down
14 changes: 5 additions & 9 deletions REPO_SURFACE_STATUS.json
Original file line number Diff line number Diff line change
Expand Up @@ -425,15 +425,6 @@
"layer": 5,
"published": false
},
"packages/core": {
"npm": "@peac/core",
"state": "deprecated",
"wire": "0.9",
"layer": "legacy",
"published": true,
"removal": "v0.13.0",
"note": "DEPRECATED. Archival of packages/core/ is coupled with the legacy /verify handler rewire that eliminates the last active consumer in apps/api/src/verifier.ts. Historical 0.9-series receipt verify-only path; use @peac/protocol + @peac/schema + @peac/crypto + @peac/kernel for current wire."
},
"packages/sdk-js": {
"npm": "@peac/sdk",
"state": "archived",
Expand Down Expand Up @@ -574,6 +565,11 @@
"layer": 6,
"published": false,
"note": "ARCHIVED in v0.13.0. Near-empty scaffold (version constant + doc comment) never published."
},
"archive/0.9.0-0.9.14/packages-core": {
"state": "archived",
"wire": "0.1",
"note": "ARCHIVED in v0.13.0. Source moved from packages/core/ to archive/0.9.0-0.9.14/packages-core/. Historical 0.9-series peac.receipt/0.9 verify-only path. Not published at v0.13.0 or later. Historical npm versions <=0.9.14 remain installable (deprecate-then-remove discipline)."
}
}
}
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ kept in the loop and the disclosure calendar is coordinated.
| `v0.12.x` | Active | Wire 0.2 (`interaction-record+jwt`) | Through the `v0.13.x` line |
| `v0.11.x` | Maintenance (security fixes only) | Wire 0.1 (`peac-receipt/0.1`) | 6 months after `v0.13.0` ships |
| `v0.10.x` and earlier | End of life | Wire 0.1 and earlier | No further updates |
| `peac.receipt/0.9` archival path | Verify-only through `@peac/core` | `peac.receipt/0.9` | Frozen; removal at `v0.13.0` |
| `peac.receipt/0.9` archival path | Historical verify-only | `peac.receipt/0.9` | Archived at `v0.13.0` |

See [Compatibility matrix](docs/COMPATIBILITY_MATRIX.md) for full runtime
and wire-format compatibility, and [Security operations](docs/SECURITY-OPERATIONS.md)
Expand Down
1 change: 0 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
},
"dependencies": {
"@hono/node-server": "^1.19.13",
"@peac/core": "workspace:*",
"@peac/crypto": "workspace:*",
"@peac/disc": "workspace:*",
"@peac/jwks-cache": "workspace:*",
Expand Down
51 changes: 35 additions & 16 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { Hono } from 'hono';
import { serve } from '@hono/node-server';
import { createV13HonoHandler } from './routes.js';
import { createVerifyV1Handler } from './verify-v1.js';
import { createIssueV1Handler } from './hosted-issue.js';
import { createIssuerHealthHandler } from './issuer-health.js';
Expand Down Expand Up @@ -34,11 +33,6 @@ export type {
HttpStatus,
} from './types.js';

// Legacy enhanced verifier (deprecated -- kept for backwards compat, will be removed)
export { VerifierV13 } from './verifier.js';
export { createV13ExpressHandler, createV13HonoHandler } from './routes.js';
export type { V13VerifyRequest, V13VerifyResponse, VerifierOptions } from './verifier.js';

// v1 verify endpoint
export { createVerifyV1Handler, resetVerifyV1RateLimit } from './verify-v1.js';

Expand Down Expand Up @@ -68,6 +62,35 @@ export const PROBLEM_TYPES = {
MISCONFIGURED_VERIFIER: 'https://www.peacprotocol.org/problems/misconfigured-verifier',
} as const;

/**
* Deprecation headers for the legacy `POST /verify` alias and any other
* route that predates `POST /v1/verify`. The alias keeps serving valid
* `/v1/verify`-shaped responses, but every response carries an RFC 9745
* `Deprecation` marker, an RFC 8594 `Sunset` date, and an RFC 8288
* `Link` relation pointing at the migration guide.
*/
export const LEGACY_VERIFY_DEPRECATION_HEADERS = {
Deprecation: 'true',
Sunset: 'Sat, 01 Nov 2026 00:00:00 GMT',
Link: '<https://www.peacprotocol.org/docs/migration>; rel="deprecation"',
} as const;

/**
* Build a Hono handler that stamps `LEGACY_VERIFY_DEPRECATION_HEADERS` on
* the response and then delegates to the canonical `/v1/verify` handler.
* Used by both the legacy `POST /verify` route and the `POST /api/v1/verify`
* alias. Production routing and tests both go through this helper so the
* two cannot drift on header set, header values, or delegation target.
*/
export function createLegacyVerifyAliasHandler(verifyV1: ReturnType<typeof createVerifyV1Handler>) {
return (c: Parameters<typeof verifyV1>[0]) => {
for (const [key, value] of Object.entries(LEGACY_VERIFY_DEPRECATION_HEADERS)) {
c.header(key, value);
}
return verifyV1(c);
};
}

// HTTP Server (when run as application)
if (import.meta.url === `file://${process.argv[1]}`) {
const app = new Hono();
Expand Down Expand Up @@ -96,20 +119,16 @@ if (import.meta.url === `file://${process.argv[1]}`) {
// Health check endpoint
app.get('/health', (c) => c.json({ ok: true }));

// Legacy verify endpoint (deprecated: removal target v0.13.0; see Sunset header)
app.post('/verify', createV13HonoHandler());

// Canonical v1 verify endpoint
const verifyV1 = createVerifyV1Handler();
app.post('/v1/verify', verifyV1);

// Deprecated alias (Sunset: Nov 1 2026)
app.post('/api/v1/verify', (c) => {
c.header('Sunset', 'Sat, 01 Nov 2026 00:00:00 GMT');
c.header('Deprecation', 'true');
c.header('Link', '<https://www.peacprotocol.org/docs/migration>; rel="deprecation"');
return verifyV1(c);
});
// Legacy verify endpoint. Kept runtime-reachable through the advertised
// Sunset date. The alias delegates in-process to the canonical v1
// handler and stamps deprecation headers on every response.
const legacyVerifyAlias = createLegacyVerifyAliasHandler(verifyV1);
app.post('/verify', legacyVerifyAlias);
app.post('/api/v1/verify', legacyVerifyAlias);

// Provisional v1 issue endpoint (BYO-key, disable via PEAC_HOSTED_ISSUE=false)
app.post('/v1/issue', createIssueV1Handler());
Expand Down
31 changes: 0 additions & 31 deletions apps/api/src/peac-core.d.ts

This file was deleted.

85 changes: 0 additions & 85 deletions apps/api/src/routes.ts

This file was deleted.

Loading
Loading