diff --git a/.well-known/agent-cards-v1.1.0.json b/.well-known/agent-cards-v1.1.0.json index eba7d3a..9d5c1fd 100644 --- a/.well-known/agent-cards-v1.1.0.json +++ b/.well-known/agent-cards-v1.1.0.json @@ -25,6 +25,7 @@ "current_release": "v1.1.0", "legacy_release": "v1.0.0 (archival compatibility only)", "publish_state": "ready-to-pin", - "license": "Apache-2.0" + "license": "Apache-2.0", + "publication_model": "root-canonical-plus-derivative-dist-pin" } } diff --git a/.well-known/agent.json b/.well-known/agent.json index 86b6114..83cc01c 100644 --- a/.well-known/agent.json +++ b/.well-known/agent.json @@ -25,6 +25,7 @@ "current_release": "v1.1.0", "legacy_release": "v1.0.0 (archival compatibility only)", "publish_state": "ready-to-pin", - "license": "Apache-2.0" + "license": "Apache-2.0", + "publication_model": "root-canonical-plus-derivative-dist-pin" } } diff --git a/ONBOARDING.md b/ONBOARDING.md index 58b3182..1395c88 100644 --- a/ONBOARDING.md +++ b/ONBOARDING.md @@ -26,6 +26,7 @@ Do not add descriptive fields to current-line cards; if the detail is not a bind - `v1.0.0` is superseded by `v1.1.0`. - Keep `v1.0.0` artifacts only for archival compatibility. - Do not use `v1.0.0` paths in new examples, new release work, or the main update flow. +- `scripts/archive/` contains historical migration helpers only; it is not part of the active validation or release path for `v1.1.0`. ## Update flow for the current line diff --git a/SECURITY.md b/SECURITY.md index 4d5e710..0ddb437 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,9 +1,14 @@ -# Security Policy — Agent Cards +# Security Policy — CommandLayer Agent Cards -Report issues that could break discovery or routing, including: +Report suspected security issues to `dev@commandlayer.org`. Use that channel for issues that could let published Agent Cards, discovery descriptors, or integrity metadata misstate identity, routing, or release provenance. -- stale or mismatched card schema bindings -- stale `_shared` references in the current line -- incorrect `entry` URIs -- manifest / discovery drift -- checksum mismatches +Examples include: + +- unauthorized or incorrect changes to current-line card bindings, schema URLs, or `entry` URIs +- manifest or discovery drift that could misroute clients +- checksum or release-bundle inconsistencies that could hide tampering +- schema or validation defects that could cause consumers to trust malformed artifacts + +Please do not open a public issue for a suspected security problem before maintainers have had a chance to review it. Include the affected file or URL, the release line, the impact you see, and any reproduction or verification steps. + +This repository is maintained by a small team, so response timing may vary. Maintainers will try to acknowledge credible reports and coordinate next steps as soon as practical, but no formal SLA is offered. diff --git a/SECURITY_PROVENANCE.md b/SECURITY_PROVENANCE.md index c88bbda..f24bd31 100644 --- a/SECURITY_PROVENANCE.md +++ b/SECURITY_PROVENANCE.md @@ -1,6 +1,6 @@ # Security & Provenance — CommandLayer Agent Cards -CommandLayer Agent Cards prove identity and routing intent. They do not prove execution success. +CommandLayer Agent Cards prove identity and routing intent. They do not prove execution success. Suspected security issues with published cards, discovery metadata, or release integrity should be reported privately to `dev@commandlayer.org` as described in `SECURITY.md`. ## Provenance model for v1.1.0 diff --git a/checksums.txt b/checksums.txt index 7ea9bff..9f1ea91 100644 --- a/checksums.txt +++ b/checksums.txt @@ -1,10 +1,10 @@ -d11253a619a5292e09896a55b24d916d503829a3c5eeaa3281edbac6d080ef64 .well-known/agent-cards-v1.1.0.json -c54994da020bbb504f9092074981bc75f4a2c6bd6a3e402681deebf659ffbe51 .well-known/agent.json -8cbbb8edf6b3ec2e65dc54ce5bdd467a63aaaad1d90bbd251a729b238ef56507 agents/v1.0.0/commercial/authorizeagent.eth.json -bfad808d0e3b107df59887c9684303b87b4867d9887c9b1a035ca8b33b115cca agents/v1.0.0/commercial/checkoutagent.eth.json -0bbd1601794b3d18f63fc331b55888cb083e0f1a37d14c3c79679c237ec0414b agents/v1.0.0/commercial/purchaseagent.eth.json -15062e72b528e2f66e58a3d83ea617a4d9e699cb1eb25a0576cbf09f3808425d agents/v1.0.0/commercial/shipagent.eth.json -4079b22e3821dbfc141b1c9baaaf1cefb20b4c68af58725aacf8428e05d2e91a agents/v1.0.0/commercial/verifyagent.eth.json +3e4062b94bfb8cfc2bbf5de5ccdcbc620d5282de5ba7caab10dd0e1a60052183 .well-known/agent-cards-v1.1.0.json +8654b246656d035a9a4c171e9b773615ca362cd746adfaed377175ca19888407 .well-known/agent.json +b7d185443a2efcf37f760f687b38963558dc82899fa249f6b0a43a6631ebb717 agents/v1.0.0/commercial/authorizeagent.eth.json +864bfc0467080e4ff6c1514f044449eed79790a5cab420588c052e6ff77c47aa agents/v1.0.0/commercial/checkoutagent.eth.json +0f718f2125c5e6b792c56156f7312e98b8ec7b6e53df24436423135f6ae4abca agents/v1.0.0/commercial/purchaseagent.eth.json +59c44856acc76e3ecbe79408048c41e236afe1d4e5f34c4615f42de83dcf7d60 agents/v1.0.0/commercial/shipagent.eth.json +4d4f6f5b17a97db262af253d851dc29d32c9b049749ae546c8774a0db59fee2b agents/v1.0.0/commercial/verifyagent.eth.json 2b14d78ad82435da6846e119bc9bf82f5b7661ccef53f4b7c25aaa50411d8812 agents/v1.0.0/commons/analyzeagent.eth.json acb40f650362582daedda35fd1dbd78b7d1b6866e26cb3ee8ca090e0d18331e1 agents/v1.0.0/commons/classifyagent.eth.json 88943a385de72550bbd7454ddc8aabc6b4bc101449b571a1966e9e8c8266040e agents/v1.0.0/commons/cleanagent.eth.json @@ -36,30 +36,30 @@ d3cde6eef58761fe5b88e3df5cb448002a289735df8f1c164fdc3b74193c61b9 dist-pin/agent 10c6ca12542dbdb21ccb1816ba7c98704789729e016b8dafe5ee2361f8b0e75c dist-pin/agent-cards/v1.0.0/meta/manifest.json d11253a619a5292e09896a55b24d916d503829a3c5eeaa3281edbac6d080ef64 dist-pin/agent-cards/v1.1.0/.well-known/agent-cards-v1.1.0.json c54994da020bbb504f9092074981bc75f4a2c6bd6a3e402681deebf659ffbe51 dist-pin/agent-cards/v1.1.0/.well-known/agent.json -9f37939c58430df6efc118ec62e56d758a2c63ff6becc33b72056dff0abd01e4 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/authorizeagent.eth.json -0c2fb22fe4d5028b3218edfbc6783fa928df09c33cac3e4ae19dd6b4fb3b1d25 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/checkoutagent.eth.json -b92447ac389a28dd6d7bb9e48b62b4dcfe2d573db9e8e46769ff7f05b70c174c dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/purchaseagent.eth.json -8845af9bfb06aae06fff06d7926417e532e417faf8b11e8d906b54769f180684 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/shipagent.eth.json -0d6ee78a0a977601d2544feed5f483d193b2d5e0790417725d1665a0e6859538 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/verifyagent.eth.json -e1b3893660ea726ff444392df7abb2eada8b7a0e89e3d18fa1da3247e2546ba9 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/analyzeagent.eth.json -66ae37ace0e04714b1965c7661237843dc699e3e2d1f68620cff45f1132fe81f dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/classifyagent.eth.json -1b56892f20d39d4780a49b8f96dd769fa7d2178f9cb04fe3c60f78d726c1889e dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/cleanagent.eth.json -eb575e806ce80fb473d771e667caa96e4e01806345292408882c92de54f2e059 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/convertagent.eth.json -0d25e3b86ca25c333a17a0cc4b9a1e0b5265dbe2bc13d88ab9da220eb5f1b613 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/describeagent.eth.json -6459519e39a9107e4294a8ad5bb46ba091933823145853aba50f38a283fbd167 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/explainagent.eth.json -60288c4c63ceb7936df2dc686b063c0b97f714afac3662f05a9f10da0b6043c4 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/fetchagent.eth.json -2c6a69e8e91d712c09994547a42bfb4043cd5abd14df2ac3f43f4d8837d2e433 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/formatagent.eth.json -7ff9756b5bcc1f989c0f36b76de8d0a8fa2d5287532dfe9717c9622eac5f6c64 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/parseagent.eth.json -1ee1a0b04cbc2488fea75458f34b0b271b7801d8e01533e4ba5dd91f2aa9ae15 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/summarizeagent.eth.json +d12610ea54b31b80758fbc68fcfaf8f20e5588097630f7d04a552bde1be458b1 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/authorizeagent.eth.json +0c7834aaf6d0692d2db9f29862ce2ae25b987cc41926bd242706da7b2847f21a dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/checkoutagent.eth.json +584a77bb4c75dc84f9e4ddf5d700a0ef2183777acd4cdf2c1761998cb2565d22 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/purchaseagent.eth.json +693f5f5cdafd76dac147f74a5c93901724b9c40a90360e28999b2cdf81e20d04 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/shipagent.eth.json +406ce4409b3a86678b95f765d4c4ecdc62dc2d735cc1c2823b149ae6743b6fc2 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commercial/verifyagent.eth.json +830324fb1fbdbc5f0796a8c87cd63683067b585e4cb73a5cd6c1563040df1d97 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/analyzeagent.eth.json +d2b00f033bdaeff370f77db9550715a8dad2c65b2c26866d9f2f75920c7500b6 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/classifyagent.eth.json +9086b5a11dc5353489946450dc3ee2d7621c042a8fee950c120b416103c8bcd2 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/cleanagent.eth.json +eeff77968e928f63329abd0839666b217651cfb4204c21a603b4dfbe707d086d dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/convertagent.eth.json +1d9f4558935cf437f860b571525850a44e522bac4590daff7dcb4917f7759edb dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/describeagent.eth.json +429fcf341f5c0d8edafbbe450f2c43b19b901b3e46d754c6f59fd046202a3aaf dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/explainagent.eth.json +73a278788f121c0c84db48ffaea900b529f57cc872afb3310bb269ebbb7e0d52 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/fetchagent.eth.json +84aca63347052d746c4c87121fa5705847844786cb521e2c6d6ad85a272df97e dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/formatagent.eth.json +f45b8bb7f745af38fce9a78c1d3a40d36a558e0c4716f59f8e70e561c89ae4e6 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/parseagent.eth.json +315eedad7b1bd8559efa8d3bdf8567c1af7b241be1c934e2ca1dfd90059d90c8 dist-pin/agent-cards/v1.1.0/agents/v1.1.0/commons/summarizeagent.eth.json 44f61b49522db5b0d058a57f4397058b3a95e1688ff6f9fd76804b2e7b46a00f dist-pin/agent-cards/v1.1.0/meta/commercial-agent.json 7493cef19304e6dc4f8991f11fdcd70d75b21e1c396684e614ead00d0892f407 dist-pin/agent-cards/v1.1.0/meta/commons-agent.json e25e455f827f166c1168dc56582ef47e6fb83fd252bca0c0e8fe0f7feba0fa7c dist-pin/agent-cards/v1.1.0/meta/manifest.json b7b573a464b3ba9f643958b716e72ce9eeb095a7c5b87bf2620eb53e7dc6afb3 dist-pin/agent-cards/v1.1.0/schemas/v1.1.0/agent.card.schema.json -0735b66ce8352a56cb18b22f60393dc669f323bcaf8e44aa1ce797e2274d524c dist-pin/agent-cards/v1.1.0/schemas/v1.1.0/agent.descriptor.schema.json +6e082c065b0ab5365b0fe3424062855587e6226a06b5ee092d77f91ea829afe2 dist-pin/agent-cards/v1.1.0/schemas/v1.1.0/agent.descriptor.schema.json 44f61b49522db5b0d058a57f4397058b3a95e1688ff6f9fd76804b2e7b46a00f meta/commercial-agent.json 7493cef19304e6dc4f8991f11fdcd70d75b21e1c396684e614ead00d0892f407 meta/commons-agent.json e25e455f827f166c1168dc56582ef47e6fb83fd252bca0c0e8fe0f7feba0fa7c meta/manifest.json ec6b2669daca50f99c9b8e04db7b8010169786788431cd74b68e547441216b8a schemas/v1.0.0/_shared/agent.card.base.schema.json c22100701ae9ebad97cfc1cb468a0369e424a0cdcec2d62968b848ef5d14369c schemas/v1.0.0/_shared/agent.descriptor.schema.json ffc066f827668ccc28b29efaf6b75def28b4931227545a6210e9faee8c4527c2 schemas/v1.1.0/agent.card.schema.json -0735b66ce8352a56cb18b22f60393dc669f323bcaf8e44aa1ce797e2274d524c schemas/v1.1.0/agent.descriptor.schema.json +6e082c065b0ab5365b0fe3424062855587e6226a06b5ee092d77f91ea829afe2 schemas/v1.1.0/agent.descriptor.schema.json diff --git a/package.json b/package.json index 88b9089..6b28c93 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "license": "Apache-2.0", "author": "Gregory Soucy", "type": "module", + "engines": { + "node": ">=22 <23" + }, "keywords": [ "agent", "agents", @@ -43,7 +46,7 @@ "validate:current": "node scripts/validate-cards.mjs --mode=current", "validate:legacy": "node scripts/validate-cards.mjs --mode=legacy", "validate:checksums": "node scripts/generate-checksums.mjs --verify", - "validate": "npm run validate:cards && npm run validate:checksums" + "validate": "npm run validate:current && npm run validate:checksums" }, "devDependencies": { "ajv": "^8.17.1", diff --git a/scripts/validate-cards.mjs b/scripts/validate-cards.mjs index b582080..8f1dfcb 100644 --- a/scripts/validate-cards.mjs +++ b/scripts/validate-cards.mjs @@ -7,7 +7,9 @@ import addFormats from "ajv-formats"; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); const ROOT = path.join(__dirname, ".."); const CURRENT_LINE = "v1.1.0"; +const LEGACY_LINE = "v1.0.0"; const CARD_HTTP_ROOT = `https://commandlayer.org/agent-cards/agents/${CURRENT_LINE}`; +const LEGACY_PLACEHOLDER_PATTERNS = ["example.com", "example.org", "TODO", "REPLACE_ME"]; const commonsVerbs = ["analyze", "classify", "clean", "convert", "describe", "explain", "fetch", "format", "parse", "summarize"]; const commercialVerbs = ["authorize", "checkout", "purchase", "ship", "verify"]; @@ -16,12 +18,30 @@ const expectedV11 = { commercial: commercialVerbs.map((verb) => `${verb}agent.eth.json`) }; +const SOURCE_ROOTS = { + [CURRENT_LINE]: { + commons: `https://raw.githubusercontent.com/commandlayer/protocol-commons/refs/tags/${CURRENT_LINE}/schemas/${CURRENT_LINE}/commons`, + commercial: `https://raw.githubusercontent.com/commandlayer/protocol-commercial/refs/tags/${CURRENT_LINE}/schemas/${CURRENT_LINE}/commercial` + }, + [LEGACY_LINE]: { + commons: "https://commandlayer.org/schemas/v1.0.0/commons", + commercial: "https://commandlayer.org/schemas/v1.0.0/commercial" + } +}; + +const MIRROR_ROOTS = { + [CURRENT_LINE]: { + commons: `https://commandlayer.org/schemas/${CURRENT_LINE}/commons`, + commercial: `https://commandlayer.org/schemas/${CURRENT_LINE}/commercial` + } +}; + const ajv = new Ajv2020({ strict: true, allErrors: true }); addFormats(ajv); function getMode() { const arg = process.argv.find((value) => value.startsWith("--mode=")); - const mode = arg ? arg.split("=")[1] : "release"; + const mode = arg ? arg.split("=")[1] : "current"; if (!["current", "legacy", "release"].includes(mode)) { throw new Error(`Unsupported validation mode: ${mode}`); } @@ -122,6 +142,8 @@ function validateCard(fullPath) { if (folderVersion === CURRENT_LINE) { const expectedSchema = `https://commandlayer.org/agent-cards/schemas/${CURRENT_LINE}/agent.card.schema.json`; + const expectedSourceRoot = SOURCE_ROOTS[CURRENT_LINE][tier]; + const expectedMirrorRoot = MIRROR_ROOTS[CURRENT_LINE][tier]; if (card.$schema !== expectedSchema) fail(`${relativePath}: stale or invalid $schema.`); if (JSON.stringify(card).includes("_shared")) fail(`${relativePath}: current ${CURRENT_LINE} card must not reference _shared.`); @@ -138,9 +160,9 @@ function validateCard(fullPath) { } } - if (folderVersion === "v1.0.0") { + if (folderVersion === LEGACY_LINE) { const text = JSON.stringify(card); - const placeholder = PLACEHOLDER_PATTERNS.find((pattern) => text.includes(pattern)); + const placeholder = LEGACY_PLACEHOLDER_PATTERNS.find((pattern) => text.includes(pattern)); if (placeholder) fail(`${relativePath}: contains legacy placeholder content (${placeholder}).`); } @@ -154,8 +176,8 @@ function validateManifestAgainstCards(cardRecords) { const manifestMap = new Map(); for (const entry of manifest.entries) { - const url = new URL(entry.agent_card); - const relativePath = decodeURIComponent(url.pathname.replace(/^\/agent-cards\//, "")); + const parsedUrl = new URL(entry.agent_card); + const relativePath = decodeURIComponent(parsedUrl.pathname.replace(/^\/agent-cards\//, "")); if (manifestMap.has(relativePath)) fail(`meta/manifest.json: duplicate manifest entry for ${relativePath}.`); manifestMap.set(relativePath, entry); @@ -187,7 +209,7 @@ function validateManifestAgainstCards(cardRecords) { expectEqual(manifest.entries.length, cardRecords.length, "meta/manifest.json: entry count must match indexed current-line cards."); expectEqual(manifest.release_lines.current, CURRENT_LINE, "meta/manifest.json: current release line mismatch."); - expectEqual(manifest.roots.cards_http, CARD_HTTP_ROOT, "meta/manifest.json: cards_http root mismatch."); + expectEqual(manifest.roots.canonical_cards_http, CARD_HTTP_ROOT, "meta/manifest.json: canonical_cards_http root mismatch."); expectEqual(manifest.updated_at, "2026-03-19T00:00:00Z", "meta/manifest.json: updated_at must reflect the current release stamp."); const commonsCount = cardRecords.filter(({ tier }) => tier === "commons").length; @@ -198,17 +220,33 @@ function validateManifestAgainstCards(cardRecords) { console.log("✅ Manifest aligned with current-line card files: meta/manifest.json"); } -function validateCurrentLine() { - console.log("▶ Validating current canonical release line (v1.1.0)."); +function validateCurrentLine(mode) { + console.log(`▶ Validating ${mode === "release" ? "release" : "current canonical"} line (${CURRENT_LINE}).`); validateDescriptor(".well-known/agent.json"); validateDescriptor(".well-known/agent-cards-v1.1.0.json"); validateExpectedV11Set(); const cardRecords = []; - for (const file of collectJsonFiles("agents")) { + for (const file of collectJsonFiles(path.join("agents", CURRENT_LINE))) { const record = validateCard(file); - if (record?.relativePath.startsWith(`agents/${CURRENT_LINE}/`)) cardRecords.push(record); + if (record) cardRecords.push(record); } validateManifestAgainstCards(cardRecords); +} + +function validateLegacyLine() { + console.log(`▶ Validating legacy compatibility line (${LEGACY_LINE}).`); + for (const file of collectJsonFiles(path.join("agents", LEGACY_LINE))) { + validateCard(file); + } +} + +function main() { + const mode = getMode(); + if (mode === "legacy") { + validateLegacyLine(); + } else { + validateCurrentLine(mode); + } if (process.exitCode) process.exit(process.exitCode); console.log(`✅ ${mode === "release" ? "Release" : mode[0].toUpperCase() + mode.slice(1)} validation completed successfully.`); }