From 1328e102f78e862c48a4736524d922d7ce27a481 Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Thu, 20 Aug 2026 19:25:21 -0400 Subject: [PATCH 1/2] fix: remove non-AGPL contribution approvals --- .github/PULL_REQUEST_TEMPLATE.md | 21 ------ .github/workflows/contributor-license.yml | 65 ------------------- AGENTS.md | 8 +-- CONTRIBUTING.md | 8 +-- docs/src/content/agents/architect.mdx | 5 -- docs/src/content/agents/engineer.mdx | 5 -- docs/src/content/agents/releaser.mdx | 5 -- docs/src/content/agents/reporter.mdx | 5 -- docs/src/content/agents/researcher.mdx | 5 -- docs/src/content/agents/reviewer.mdx | 5 -- docs/src/content/agents/technical-writer.mdx | 5 -- docs/src/content/agents/tester.mdx | 5 -- package-lock.json | 6 +- package.json | 2 +- .../project-contribution-attestation.ts | 16 ----- src/agents/index.ts | 1 - .../project-contribution-attestation.test.ts | 10 --- .../non-agpl-contribution-policy.test.ts | 16 +++++ 18 files changed, 26 insertions(+), 167 deletions(-) delete mode 100644 .github/workflows/contributor-license.yml delete mode 100644 src/agents/contributions/project-contribution-attestation.ts delete mode 100644 tests/unit/agents/contributions/project-contribution-attestation.test.ts create mode 100644 tests/unit/agents/non-agpl-contribution-policy.test.ts diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cb91eb8d..9dbb6d39 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -39,8 +39,6 @@ Contributor mode (select one): -- [ ] I ran the narrowest relevant package verification and documented any checks that could not be run. - ## Risk and rollback @@ -49,25 +47,6 @@ Contributor mode (select one): -## Contribution grant (human action required) - -The accountable human must review [CONTRIBUTING.md](https://github.com/treeseed-ai/agent/blob/main/CONTRIBUTING.md) and check the affirmation below. Agents must leave it unchecked for the human. - - - -- [ ] I have read `CONTRIBUTING.md`, have the right to submit this contribution, and intentionally submit it for inclusion under the Apache License, Version 2.0, without additional terms or conditions, as described by Section 5. - -## Agent contribution attestation - -Governed agents must leave the human affirmation unchecked. TreeSeed populates the managed block below only when an active project authorization, assignment, agent, capacity provider, repository, base SHA, and head SHA all match. Agents cannot create or broaden that authorization. - - -Pending — TreeSeed will replace this text for an authorized agent contribution. - - ## Submission checklist - [ ] The change is bounded to the stated work item and target repository. diff --git a/.github/workflows/contributor-license.yml b/.github/workflows/contributor-license.yml deleted file mode 100644 index 790d8d58..00000000 --- a/.github/workflows/contributor-license.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Contributor License Grant - -on: - pull_request_target: - types: [opened, edited, reopened, synchronize] - -permissions: - contents: read - pull-requests: read - -jobs: - affirmation: - runs-on: ubuntu-latest - steps: - - name: Verify human grant or delegated agent attestation - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b - with: - script: | - const { createHash, createPublicKey, verify } = require('node:crypto'); - const pr = context.payload.pull_request; - const body = pr?.body ?? ''; - const checked = (label) => body.split(/\r?\n/u).some((line) => line.trim() === `- [x] ${label}` || line.trim() === `- [X] ${label}`); - const humanMode = checked('Human-authored'); - const agentMode = checked('Agent-assisted under human authority') || checked('Agent-authored under human authority'); - const grant = 'I have read `CONTRIBUTING.md`, have the right to submit this contribution, and intentionally submit it for inclusion under the Apache License, Version 2.0, without additional terms or conditions, as described by Section 5.'; - const humanGrant = checked(grant); - if (humanMode) { - if (agentMode) return core.setFailed('Select exactly one contributor mode.'); - if (!humanGrant) return core.setFailed('Check the human Contribution grant affirmation before this contribution can be merged.'); - return; - } - if (!agentMode) return core.setFailed('Select one contributor mode.'); - if (humanGrant) return core.setFailed('An agent contribution must not check or claim the Human contribution affirmation.'); - const start = ''; - const end = ''; - const block = body.slice(body.indexOf(start), body.indexOf(end)); - const encoded = /```json treeseed-contribution-attestation\s+([\s\S]*?)\s+```/u.exec(block)?.[1]; - if (!encoded) return core.setFailed('A managed TreeSeed agent contribution attestation is required.'); - let bundle; - try { bundle = JSON.parse(encoded); } catch { return core.setFailed('The managed contribution attestation is invalid JSON.'); } - async function baseFile(path) { - const response = await github.rest.repos.getContent({ owner: context.repo.owner, repo: context.repo.repo, path, ref: pr.base.sha }); - if (Array.isArray(response.data) || !response.data.content) throw new Error(`${path} is not a file.`); - return Buffer.from(response.data.content, response.data.encoding ?? 'base64').toString('utf8'); - } - let policy, guidance; - try { policy = JSON.parse(await baseFile('.treeseed/contribution-policy.json')); guidance = await baseFile('AGENTS.md'); } - catch (error) { return core.setFailed(`The base branch has no trusted project contribution policy: ${error.message}`); } - if (!guidance.includes('delegated-project-authorization') || !guidance.includes('contribution_attestation')) return core.setFailed('Base AGENTS.md does not permit delegated contribution attestation.'); - const authorization = bundle.authorization; const attestation = bundle.attestation; - if (JSON.stringify(authorization) !== JSON.stringify(policy.activeAuthorization)) return core.setFailed('The attestation authorization does not match the base branch project policy.'); - const expectedRepo = { provider: 'github', owner: context.repo.owner, name: context.repo.repo }; - const exact = attestation?.base?.sha === pr.base.sha && attestation?.head?.sha === pr.head.sha && attestation?.base?.branch === pr.base.ref && attestation?.head?.branch === pr.head.ref; - if (!exact) return core.setFailed('The agent contribution attestation is stale for the exact PR base or head.'); - if (JSON.stringify(authorization?.repository) !== JSON.stringify(expectedRepo) || JSON.stringify(attestation?.repository) !== JSON.stringify(expectedRepo)) return core.setFailed('Repository authorization does not match this PR.'); - if (authorization.status !== 'active' || !Number.isFinite(Date.parse(authorization.effectiveAt)) || Date.parse(authorization.effectiveAt) > Date.now() || (authorization.expiresAt && Date.parse(authorization.expiresAt) <= Date.now())) return core.setFailed('Project contribution authorization is inactive, not yet effective, or expired.'); - if (!authorization.allowedActions.includes('populate_pr_attestation')) return core.setFailed('Project authorization does not permit PR attestation.'); - if (!authorization.agentIds.includes(attestation.agentId) || !authorization.capacityProviderIds.includes(attestation.capacityProviderId) || !authorization.contributionModes.includes(attestation.mode) || !authorization.targetBranches.includes(pr.base.ref)) return core.setFailed('Agent, provider, contribution mode, or target branch is not authorized.'); - if (attestation.authorization.id !== authorization.id || attestation.authorization.generation !== authorization.generation || attestation.authorization.digest !== authorization.grant.digest) return core.setFailed('Authorization generation or grant digest does not match.'); - const canonical = (value) => Array.isArray(value) ? value.map(canonical) : value && typeof value === 'object' ? Object.fromEntries(Object.entries(value).sort(([a],[b]) => a.localeCompare(b)).map(([key,item]) => [key,canonical(item)])) : value; - const { receipt, ...payload } = attestation; - const bytes = Buffer.from(JSON.stringify(canonical({ ...payload, receipt: { keyId: receipt.keyId, algorithm: receipt.algorithm } })), 'utf8'); - const digest = `sha256:${createHash('sha256').update(bytes).digest('base64url')}`; - if (digest !== receipt.payloadDigest || receipt.keyId !== authorization.receiptKey.keyId || receipt.algorithm !== 'Ed25519') return core.setFailed('Contribution receipt digest or key binding is invalid.'); - if (!verify(null, bytes, createPublicKey({ key: authorization.receiptKey.publicKeyJwk, format: 'jwk' }), Buffer.from(receipt.signature, 'base64url'))) return core.setFailed('Contribution receipt signature is invalid.'); diff --git a/AGENTS.md b/AGENTS.md index 191deaac..7dd04d00 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,5 @@ -# Agent runtime contribution policy +# Agent runtime workspace guidance -Agents may prepare the managed **Agent contribution attestation** only when their definition enables `delegated-project-authorization`, the assignment and capacity grant include `contribution_attestation`, and the trusted API issues a receipt bound to the exact repository, agent, capacity provider, assignment, base SHA, and head SHA. +The Agent package is an Apache-2.0 repository. It has no contributor-grant checkbox, approved-committer allowlist, or contribution-attestation requirement. Human and agent changes use the same durable pull-request record and the same exact-head verification, review, staging, and release gates. -Agents must never check or edit the **Human contribution affirmation** and may not create, broaden, renew, revoke, or supersede a project contribution authorization. The Agent runtime verifies the API signature and returns only the managed body block; GitHub token/App custody and PR mutation remain in the trusted provider/API boundary. - -Missing, stale, mismatched, expired, revoked, or unsigned authority fails closed. Never pass GitHub credentials, provider private keys, membership credentials, or signing secrets into an agent execution workspace. +Agents must act only within assignment and capacity-provider authority, preserve exact repository and commit evidence, and keep GitHub tokens, provider private keys, membership credentials, and runtime secrets outside agent execution workspaces. Repository publication remains in the trusted provider/API boundary. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac337a5b..60539285 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,7 @@ # Contributing to TreeSeed Agent -Human and governed-agent contributions use the same durable pull-request record. Select exactly one contributor mode and preserve the exact base/head refs, work authority, verification, commits, and completion summary. +Human and agent contributions use the same durable pull-request record. Select the contributor mode and preserve the exact base/head refs, work authority, verification, commits, risk, rollback, and completion summary. -Human contributors must check the template affirmation themselves. Governed agents must leave it unchecked and may populate only the TreeSeed-managed attestation block when an active project authorization, assignment, agent, capacity provider, repository, base, and head all match. +This repository is licensed under Apache-2.0. In accordance with Section 5 of that license, an intentionally submitted contribution is provided under Apache-2.0 without additional terms unless you explicitly state otherwise. The repository does not require a separate contributor-grant checkbox, standing contributor authorization, or approved-committer allowlist. -By intentionally submitting a Contribution for inclusion in this Apache-2.0 project, and unless you explicitly state otherwise, the Contribution is submitted under the Apache License, Version 2.0 without additional terms or conditions as described by Section 5. Review [the repository license](LICENSE) and the [official Apache License 2.0 text](https://www.apache.org/licenses/LICENSE-2.0) before affirming. - -Do not submit code, documentation, or other material you do not have the right to contribute. An agent cannot create, broaden, renew, revoke, or impersonate a human contribution authorization. +Do not submit code, documentation, or other material you do not have the right to contribute. Review [LICENSE](LICENSE) before submitting. diff --git a/docs/src/content/agents/architect.mdx b/docs/src/content/agents/architect.mdx index c0fc4120..d0bfc2b5 100644 --- a/docs/src/content/agents/architect.mdx +++ b/docs/src/content/agents/architect.mdx @@ -15,11 +15,6 @@ groupIds: - agent - architecture - engineering-team -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Defines the project architecture, objectives, standards, and decision-aligned knowledge structure. responsibilities: diff --git a/docs/src/content/agents/engineer.mdx b/docs/src/content/agents/engineer.mdx index 4fdea6fd..b6c89e3c 100644 --- a/docs/src/content/agents/engineer.mdx +++ b/docs/src/content/agents/engineer.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering - engineering-team -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Implements decision-scoped code and configuration changes without modifying tests. responsibilities: diff --git a/docs/src/content/agents/releaser.mdx b/docs/src/content/agents/releaser.mdx index 7a0373b7..959e3c49 100644 --- a/docs/src/content/agents/releaser.mdx +++ b/docs/src/content/agents/releaser.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - release -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Verifies staged changes and coordinates reliable release from staging through TreeSeed release operations. responsibilities: diff --git a/docs/src/content/agents/reporter.mdx b/docs/src/content/agents/reporter.mdx index 0317c0e7..cc8492cc 100644 --- a/docs/src/content/agents/reporter.mdx +++ b/docs/src/content/agents/reporter.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - reporting -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Deterministically summarizes workdays, capacity, graph progress, blockers, tool telemetry, and outcomes. responsibilities: diff --git a/docs/src/content/agents/researcher.mdx b/docs/src/content/agents/researcher.mdx index de97132f..c8e27f92 100644 --- a/docs/src/content/agents/researcher.mdx +++ b/docs/src/content/agents/researcher.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - research -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Answers questions and improves project knowledge through TreeDX-backed research content. responsibilities: diff --git a/docs/src/content/agents/reviewer.mdx b/docs/src/content/agents/reviewer.mdx index d732fd5c..4d554965 100644 --- a/docs/src/content/agents/reviewer.mdx +++ b/docs/src/content/agents/reviewer.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - review -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Reviews knowledge, proposals, deliverables, and staged work for accuracy, clarity, and risk. responsibilities: diff --git a/docs/src/content/agents/technical-writer.mdx b/docs/src/content/agents/technical-writer.mdx index 878c85b1..136344d2 100644 --- a/docs/src/content/agents/technical-writer.mdx +++ b/docs/src/content/agents/technical-writer.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - technical-writing -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Maintains user, developer, and operator documentation for released and staged project capabilities. responsibilities: diff --git a/docs/src/content/agents/tester.mdx b/docs/src/content/agents/tester.mdx index 864917a7..2c5c658f 100644 --- a/docs/src/content/agents/tester.mdx +++ b/docs/src/content/agents/tester.mdx @@ -15,11 +15,6 @@ groupIds: - agent - engineering-team - testing -contribution: - mode: delegated-project-authorization - mayPopulatePrAttestation: true - requiredCapability: contribution_attestation - requireExactHead: true identity: purpose: Creates tests before implementation and verifies behavior without modifying implementation code. responsibilities: diff --git a/package-lock.json b/package-lock.json index 71436dcd..d6dcb9d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", "@openai/codex-sdk": "^0.130.0", - "@treeseed/sdk": "github:treeseed-ai/sdk#5db07e79bbd32bcd753d7600d15b7412357fc8c5", + "@treeseed/sdk": "github:treeseed-ai/sdk#92a66135fbda5575bee058b0ab25339c6c7d6398", "esbuild": "0.28.0", "hono": "^4.8.2", "typescript": "^5.9.3", @@ -3703,8 +3703,8 @@ }, "node_modules/@treeseed/sdk": { "version": "0.12.63-dev.fix-sdk-package-lock-integrity.20260818T124913Z", - "resolved": "git+ssh://git@github.com/treeseed-ai/sdk.git#5db07e79bbd32bcd753d7600d15b7412357fc8c5", - "integrity": "sha512-WEuDEN/5h/DJWdul+QeYl9K2Tpc70LWdvdo8zxuktat5f9Vi67OFd424v94fTok9SDrIAKzS00pzchIdecUmsQ==", + "resolved": "git+ssh://git@github.com/treeseed-ai/sdk.git#92a66135fbda5575bee058b0ab25339c6c7d6398", + "integrity": "sha512-6w9qNqZCmHdgme7C3Ab14xUz5UnAz0HPq5+u1t3fE9Wb3OStn4TQbS6kGJ/l9wwPdoixjD0V2VOcjmjXIzsiuA==", "license": "Apache-2.0", "dependencies": { "@github/copilot": "1.0.39", diff --git a/package.json b/package.json index c438993b..58b3e73b 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", "@openai/codex-sdk": "^0.130.0", - "@treeseed/sdk": "github:treeseed-ai/sdk#5db07e79bbd32bcd753d7600d15b7412357fc8c5", + "@treeseed/sdk": "github:treeseed-ai/sdk#92a66135fbda5575bee058b0ab25339c6c7d6398", "esbuild": "0.28.0", "hono": "^4.8.2", "typescript": "^5.9.3", diff --git a/src/agents/contributions/project-contribution-attestation.ts b/src/agents/contributions/project-contribution-attestation.ts deleted file mode 100644 index 89b44fce..00000000 --- a/src/agents/contributions/project-contribution-attestation.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { renderAgentContributionAttestationBlock,validateAgentContributionAttestation,verifyAgentContributionReceipt,type AgentContributionAttestationBundle,type AgentContributionPermission } from '@treeseed/sdk/work-providers'; - -type Client={request(path:string,options?:Record):Promise}; -const record=(value:unknown):Record=>value&&typeof value==='object'&&!Array.isArray(value)?value as Record:{}; - -export async function prepareProjectContributionAttestation(input:{client:Client;permission:AgentContributionPermission;availableCapabilities:string[];projectId:string;assignmentId:string;checkpointId?:string|null;agentId:string;capacityProviderId:string;mode:'agent-assisted'|'agent-authored';repository:{provider:string;owner:string;name:string};base:{branch:string;sha:string};head:{branch:string;sha:string};}) { - if(input.permission.mode!=='delegated-project-authorization'||input.permission.mayPopulatePrAttestation!==true||input.permission.requireExactHead!==true)return {ok:false as const,code:'contribution_attestation_agent_permission_denied'}; - if(!input.availableCapabilities.includes(input.permission.requiredCapability))return {ok:false as const,code:'contribution_attestation_capability_missing'}; - const response=record(await input.client.request(`/v1/projects/${encodeURIComponent(input.projectId)}/contribution-attestations`,{method:'POST',body:{assignmentId:input.assignmentId,checkpointId:input.checkpointId??null,agentId:input.agentId,capacityProviderId:input.capacityProviderId,mode:input.mode,repository:input.repository,base:input.base,head:input.head},requireAuth:true})); - if(response.ok!==true)return {ok:false as const,code:String(response.code??'contribution_attestation_issuance_failed'),diagnostics:response.diagnostics??[]}; - const bundle=record(response.payload) as AgentContributionAttestationBundle; - const validation=validateAgentContributionAttestation({authorization:bundle.authorization,attestation:bundle.attestation,expected:{projectId:input.projectId,repository:input.repository,assignmentId:input.assignmentId,baseBranch:input.base.branch,baseSha:input.base.sha,headBranch:input.head.branch,headSha:input.head.sha}}); - if(!validation.ok)return {ok:false as const,code:'contribution_attestation_validation_failed',diagnostics:validation.diagnostics}; - if(!await verifyAgentContributionReceipt(bundle.attestation,bundle.authorization))return {ok:false as const,code:'contribution_attestation_signature_invalid'}; - return {ok:true as const,bundle,managedBodyBlock:renderAgentContributionAttestationBlock(bundle)}; -} diff --git a/src/agents/index.ts b/src/agents/index.ts index 705eebe5..242c7b2e 100644 --- a/src/agents/index.ts +++ b/src/agents/index.ts @@ -1,2 +1 @@ export { listRegisteredAgentHandlers, resolveAgentHandler } from './support/registry.ts'; -export { prepareProjectContributionAttestation } from './contributions/project-contribution-attestation.ts'; diff --git a/tests/unit/agents/contributions/project-contribution-attestation.test.ts b/tests/unit/agents/contributions/project-contribution-attestation.test.ts deleted file mode 100644 index da3f0a35..00000000 --- a/tests/unit/agents/contributions/project-contribution-attestation.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { contributionAttestationPayload,contributionAttestationPayloadDigest,TREESEED_AGENT_CONTRIBUTION_ATTESTATION_VERSION,TREESEED_CONTRIBUTION_GRANT_VERSION,type AgentContributionAttestation,type ProjectContributionAuthorization } from '@treeseed/sdk/work-providers'; -import { describe,expect,it } from 'vitest'; -import { prepareProjectContributionAttestation } from '../../../../src/agents/contributions/project-contribution-attestation.ts'; - -async function bundle(){const pair=await crypto.subtle.generateKey({name:'Ed25519'},true,['sign','verify']);const publicKeyJwk=await crypto.subtle.exportKey('jwk',pair.publicKey);const authorization:ProjectContributionAuthorization={schemaVersion:TREESEED_CONTRIBUTION_GRANT_VERSION,id:'grant-1',generation:1,status:'active',projectId:'project-1',repository:{provider:'github',owner:'treeseed-ai',name:'agent'},grant:{version:'v1',digest:'sha256:grant'},receiptKey:{keyId:'key-1',algorithm:'Ed25519',publicKeyJwk},authorizedBy:{principalId:'human-1'},agentIds:['agent-1'],capacityProviderIds:['provider-1'],contributionModes:['agent-authored'],targetBranches:['staging'],allowedActions:['populate_pr_attestation'],effectiveAt:'2026-08-20T12:00:00.000Z',expiresAt:'2027-08-20T12:00:00.000Z'};const attestation:AgentContributionAttestation={schemaVersion:TREESEED_AGENT_CONTRIBUTION_ATTESTATION_VERSION,authorization:{id:'grant-1',generation:1,digest:'sha256:grant'},projectId:'project-1',repository:authorization.repository,assignmentId:'assignment-1',agentId:'agent-1',capacityProviderId:'provider-1',mode:'agent-authored',base:{branch:'staging',sha:'a'.repeat(40)},head:{branch:'codex/assignment-1',sha:'b'.repeat(40)},issuedAt:'2026-08-20T13:00:00.000Z',receipt:{keyId:'key-1',algorithm:'Ed25519',payloadDigest:'pending',signature:'pending'}};attestation.receipt.payloadDigest=await contributionAttestationPayloadDigest(attestation);attestation.receipt.signature=Buffer.from(await crypto.subtle.sign('Ed25519',pair.privateKey,contributionAttestationPayload(attestation))).toString('base64url');return{authorization,attestation};} -const input=()=>({permission:{mode:'delegated-project-authorization' as const,mayPopulatePrAttestation:true,requiredCapability:'contribution_attestation' as const,requireExactHead:true as const},availableCapabilities:['contribution_attestation'],projectId:'project-1',assignmentId:'assignment-1',agentId:'agent-1',capacityProviderId:'provider-1',mode:'agent-authored' as const,repository:{provider:'github',owner:'treeseed-ai',name:'agent'},base:{branch:'staging',sha:'a'.repeat(40)},head:{branch:'codex/assignment-1',sha:'b'.repeat(40)}}); -describe('agent contribution attestation',()=>{ - it('requests, verifies, and renders only an API-signed exact-head bundle',async()=>{const value=await bundle();const result=await prepareProjectContributionAttestation({...input(),client:{request:async()=>({ok:true,payload:value})}});expect(result.ok).toBe(true);if(result.ok)expect(result.managedBodyBlock).toContain('treeseed:contribution-attestation:start');}); - it('fails before API access without explicit capability',async()=>{let calls=0;const result=await prepareProjectContributionAttestation({...input(),availableCapabilities:[],client:{request:async()=>{calls+=1;return{};}}});expect(result).toEqual({ok:false,code:'contribution_attestation_capability_missing'});expect(calls).toBe(0);}); -}); diff --git a/tests/unit/agents/non-agpl-contribution-policy.test.ts b/tests/unit/agents/non-agpl-contribution-policy.test.ts new file mode 100644 index 00000000..32698e22 --- /dev/null +++ b/tests/unit/agents/non-agpl-contribution-policy.test.ts @@ -0,0 +1,16 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { describe, expect, it } from 'vitest'; + +describe('Agent contribution policy', () => { + it('does not impose the AGPL commercial-license approval process', () => { + const root = process.cwd(); + const template = readFileSync(resolve(root, '.github/PULL_REQUEST_TEMPLATE.md'), 'utf8'); + const guidance = readFileSync(resolve(root, 'CONTRIBUTING.md'), 'utf8'); + expect(JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8')).license).toBe('Apache-2.0'); + expect(existsSync(resolve(root, '.github/workflows/contributor-license.yml'))).toBe(false); + expect(existsSync(resolve(root, '.github/approved-committers.json'))).toBe(false); + expect(template).not.toMatch(/Contribution grant|contribution-attestation/u); + expect(guidance).toMatch(/does not require a separate contributor-grant checkbox/u); + }); +}); From 602fe2ee3f4c8ae53fd33d6ff1aeff35dbb630ab Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Thu, 20 Aug 2026 19:29:07 -0400 Subject: [PATCH 2/2] test: place contribution policy under owned root --- .../{ => contributions}/non-agpl-contribution-policy.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unit/agents/{ => contributions}/non-agpl-contribution-policy.test.ts (100%) diff --git a/tests/unit/agents/non-agpl-contribution-policy.test.ts b/tests/unit/agents/contributions/non-agpl-contribution-policy.test.ts similarity index 100% rename from tests/unit/agents/non-agpl-contribution-policy.test.ts rename to tests/unit/agents/contributions/non-agpl-contribution-policy.test.ts