diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0b464d5..368616f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,14 @@ blank_issues_enabled: false contact_links: - - name: Security report - url: https://github.com/0xprogrammable/programmable-registry/security/advisories/new - about: Report vulnerabilities privately. Do not open a public security issue. - - name: Builder support - url: https://github.com/0xprogrammable/programmable-v4-builder/discussions - about: Ask how to build, verify, submit, or discover a project. + - name: Report a vulnerability privately + url: https://github.com/0xprogrammable/apply/security/advisories/new + about: Report security-sensitive findings privately. Do not open a public issue. + - name: Ask an Apply question + url: https://github.com/0xprogrammable/apply/discussions/new?category=q-a + about: Ask about applications, review records, registry data, or integrations. + - name: Propose an Apply idea + url: https://github.com/0xprogrammable/apply/discussions/new?category=ideas + about: Discuss a review-rule, registry, or workflow improvement before opening a pull request. + - name: Get Hookbuilder support + url: https://github.com/0xprogrammable/hookbuilder/issues/new/choose + about: Report Builder bugs or propose building capabilities and templates. diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 0000000..8cd26f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,34 @@ +name: Documentation correction +description: Report inaccurate, missing, or unclear Apply documentation. +title: "[Docs] " +labels: + - documentation +body: + - type: input + id: location + attributes: + label: Page or file + description: Link to the exact page, file, or section. + placeholder: https://github.com/0xprogrammable/apply/blob/main/README.md + validations: + required: true + - type: textarea + id: problem + attributes: + label: What is inaccurate or missing? + validations: + required: true + - type: textarea + id: correction + attributes: + label: Suggested correction + description: State the verifiable replacement or missing information. + validations: + required: true + - type: checkboxes + id: safety + attributes: + label: Public-report confirmation + options: + - label: This report contains no secret, personal data, private repository content, wallet material, or unpatched exploit. + required: true diff --git a/.github/ISSUE_TEMPLATE/review-or-registry-bug.yml b/.github/ISSUE_TEMPLATE/review-or-registry-bug.yml new file mode 100644 index 0000000..7300f12 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/review-or-registry-bug.yml @@ -0,0 +1,69 @@ +name: Checker or registry bug +description: Report a reproducible, non-sensitive problem in Apply. +title: "[Bug] " +labels: + - bug +body: + - type: markdown + attributes: + value: | + Use this form for public, non-sensitive defects. Report exploitable vulnerabilities privately through [GitHub Security](https://github.com/0xprogrammable/apply/security/advisories/new). + - type: dropdown + id: component + attributes: + label: Affected component + options: + - Public checker or policy + - Application intake + - Registry or discovery data + - Schema + - GitHub workflow + - Documentation + - Other + validations: + required: true + - type: input + id: revision + attributes: + label: Apply release or commit + description: Provide the exact tag or 40-character commit when possible. + placeholder: v1.1.0 or ba485e37561763179a694130b59de0cd09954b16 + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Minimal reproduction + description: List the exact commands and smallest public input needed to reproduce the problem. + placeholder: | + 1. Run ... + 2. Provide ... + 3. Observe ... + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual result + description: Include sanitized output or a public link. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected result + description: Explain the objective result you expected and why. + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: Include the operating system, Node.js version, and relevant command or host. + - type: checkboxes + id: safety + attributes: + label: Public-report confirmation + options: + - label: This report contains no secret, personal data, private repository content, wallet material, or unpatched exploit. + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 752d8fc..f36ac80 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,5 @@ @@ -7,11 +7,13 @@ Passing intake is not acceptance, an audit, deployment approval, or availability ## Contribution type - [ ] Generated six-file application package -- [ ] Registry maintenance +- [ ] Apply repository maintenance +- [ ] Open Review Standard maintenance ## Evidence -Describe the exact source revision, reason for the change, and checks run. For a generated application, keep the Builder-generated title and body unchanged. +Describe the exact source revision, reason for the change, and checks run. For a generated application, keep the +Hookbuilder-generated title and body unchanged. ## Checklist diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..7d5917d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,41 @@ +name: CodeQL + +on: + pull_request: + branches: + - main + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + security-events: write + +concurrency: + group: apply-codeql-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + codeql: + name: CodeQL + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + fetch-depth: 1 + lfs: false + submodules: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + with: + languages: javascript-typescript + + - name: Analyze + uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 diff --git a/.github/workflows/verify-hook-builder.yml b/.github/workflows/verify-hook-builder.yml index 18f771a..6518a7b 100644 --- a/.github/workflows/verify-hook-builder.yml +++ b/.github/workflows/verify-hook-builder.yml @@ -4,10 +4,6 @@ on: pull_request_target: branches: - main - push: - branches: - - main - workflow_dispatch: permissions: contents: read @@ -156,37 +152,3 @@ jobs: if: steps.classify.outputs.mode == 'no-op' shell: bash run: echo "No current Registry intake content changed." - - trusted-post-merge: - if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - timeout-minutes: 20 - - steps: - - name: Checkout trusted revision - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - path: source - persist-credentials: false - fetch-depth: 1 - lfs: false - submodules: false - - - name: Set up Node - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: 20 - - - name: Verify trusted Registry revision - working-directory: source - run: npm test - - - name: Validate all maintained applications - shell: bash - run: | - set -euo pipefail - source_root="$GITHUB_WORKSPACE/source" - node "$source_root/scripts/verify-public-hook-application.mjs" \ - --verify-maintained \ - --repository-root "$source_root" diff --git a/.github/workflows/verify-post-merge.yml b/.github/workflows/verify-post-merge.yml new file mode 100644 index 0000000..2435be4 --- /dev/null +++ b/.github/workflows/verify-post-merge.yml @@ -0,0 +1,48 @@ +name: Verify trusted main + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: apply-post-merge-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + trusted-post-merge: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout trusted revision + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + path: source + persist-credentials: false + fetch-depth: 1 + lfs: false + submodules: false + + - name: Set up Node + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 20 + + - name: Verify trusted Apply revision + working-directory: source + run: npm test + + - name: Validate all maintained applications + shell: bash + run: | + set -euo pipefail + source_root="$GITHUB_WORKSPACE/source" + node "$source_root/scripts/verify-public-hook-application.mjs" \ + --verify-maintained \ + --repository-root "$source_root" diff --git a/AGENTS.md b/AGENTS.md index 795f6ca..b02da42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,11 +1,11 @@ -# Registry contribution contract +# Apply contribution contract This repository is the public application ledger and canonical discovery registry for Programmable projects built with -the Programmable v4 Builder. +Hookbuilder. ## Authority boundaries -- Builder projects remain in builder-controlled public GitHub repositories. +- Applicant projects remain in applicant-owned public GitHub repositories. - `submissions/` contains bounded, untrusted application records. A submission never edits `registry/`. - `registry/projects/` contains maintainer-authored records only. A record describes evidence; it is not an audit or safety guarantee. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04db3d2..4c3be6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,18 +1,19 @@ # Contributing -There are two intentionally separate contribution paths. +There are three intentionally separate contribution paths. Keep each pull request to one path. ## Application pull requests -Use the released Programmable v4 Builder. An application pull request changes exactly one generated six-file directory +Use the released [Hookbuilder](https://github.com/0xprogrammable/hookbuilder). An application pull request changes +exactly one generated six-file directory under `submissions//`. Do not add project source, workflows, registry records, vendored code, or policy -changes. The complete project stays in the builder-controlled public repository bound by numeric repository id, commit, +changes. The complete project stays in the applicant-owned public repository bound by numeric repository id, commit, tree, and evidence digests. An intake pass proves only that the public record is structurally valid and bound to reachable source. It is not acceptance, an audit, deployment approval, provider support, availability, or Uniswap endorsement. -## Registry maintenance +## Apply repository maintenance Maintainers use a separate pull request for schemas, project records, generated indexes, documentation, workflows, tests, or the pinned Builder validation dependency. Run `npm test` and include the exact source evidence for every status diff --git a/README.md b/README.md index f634ac2..6b177eb 100644 --- a/README.md +++ b/README.md @@ -5,84 +5,136 @@

Programmable Apply

- Public applications, open review rules and the discovery ledger for Programmable projects. + Open review rules, public applications, and canonical discovery records for Programmable projects.

-The Registry gives agents, reviewers, and the Programmable Explorer one GitHub-backed source for what has been -submitted, reviewed, deployed, made available, suspended, or retired. It never turns a local check, merged application, -similarity match, deployment, or indexer observation into a safety guarantee. +

+ Repository verification + CodeQL analysis + Latest release + MIT License +

-## Build, apply, review +

+ Read the standard · + Run the checker · + Report a finding +

-```mermaid -flowchart LR - B["Builder-owned project repository"] -->|"six-file application PR"| R["Programmable Apply"] - S["Hookbuilder"] -->|"build, check, submit"| B - R -->|"open review standard"| V["Review"] - V -->|"exact-revision record"| E["Programmable Explorer"] -``` +Programmable Apply publishes the [Open Review Standard](docs/OPEN_REVIEW_STANDARD.md), a deterministic local checker, +the public application ledger, and a versioned discovery registry. Complete project source stays in the applicant-owned +public repository. + +> [!IMPORTANT] +> **Public application intake is currently in prelaunch.** The standard, checker, schemas, examples, and discovery +> registry are public today. A matching Hookbuilder release will activate new applications to this repository. Existing +> applications keep their original GitHub review threads. + +A local checker result, passing pull request, merged application, registry match, deployment, or indexer observation is +never presented as a safety guarantee or launch right. + +## Open Review Standard + +The standard defines evidence requirements across five decision-critical areas: artifact identity, functionality, +disclosure, integrity, and launch compatibility. It does not rank ideas or reject a project because its mechanics, fees, +losses, architecture, or tokenomics are unusual. -- The builder's repository owns the complete project. -- [`hookbuilder`](https://github.com/0xprogrammable/hookbuilder) owns agent behavior, rules, - templates, checks, and the GitHub client. -- This repository owns applications and discovery records. -- [`programmable`](https://github.com/0xprogrammable/programmable) owns the platform, contracts, and Explorer. +Unknown platform-owned evidence remains `platform_analysis_pending`. A hard block requires a complete, revision-bound, +independently replayed witness supported by the current policy. A model opinion, scanner score, label, or incomplete +witness cannot hard-block a project. -## Open review standard +The public checker validates a closed review input and applies the published policy deterministically. It does not fetch +project repositories, reproduce evidence, perform an audit, sign a platform decision, deploy contracts, or issue a +launch permit. -The selection rules are public. They judge exact evidence, not whether an idea is familiar, fashionable or profitable. -Unknown platform-owned behavior stays pending; it is not silently called unsafe. A hard block requires a complete, -revision-bound and independently replayed witness. +Read the complete [Open Review Standard](docs/OPEN_REVIEW_STANDARD.md) and the machine-readable +[policy](review/policy.v1.json). -Read the [Open Review Standard](docs/OPEN_REVIEW_STANDARD.md), inspect the -[policy](review/policy.v1.json), or run a public example: +## Run the checker + +Node.js 20 or newer is required. The checker has no runtime dependencies and never executes candidate code. ```bash +git clone --depth 1 https://github.com/0xprogrammable/apply.git +cd apply npm run review -- review/examples/disclosed-high-fee.json ``` -The local result never signs an approval or grants launch rights. +The bundled example returns `launch_ready` together with `checkerOnly: true`, `launchAuthorized: false`, and +`independentAudit: false`. Inspect the [examples](review/examples), +[input schema](review/schemas/open-review-input.v1.schema.json), and +[decision schema](review/schemas/open-review-decision.v1.schema.json). -## Current registry +Run the complete repository gate with: -[`registry/index.json`](registry/index.json) is the small discovery entry point. Every entry binds one closed record by -SHA-256. [`registry/search-index.json`](registry/search-index.json) contains only bounded discovery metadata; agents -fetch a full project record only after a match. +```bash +npm test +``` -Statuses are deliberately separate: `design`, `candidate`, `accepted`, `deployed`, `available`, `suspended`, and -`retired`. Pending pull requests are unreviewed applications and are never inserted into the canonical registry merely -because their intake check passed. +## How it works -Read the small contracts before integrating: +1. **Build.** Project source stays in its own public GitHub repository. +2. **Prepare.** When intake opens, [Hookbuilder](https://github.com/0xprogrammable/hookbuilder) prepares six generated + application files bound to one repository id, commit, tree, configuration, and evidence set. +3. **Review.** Programmable Apply validates the bounded application. Review evidence and any later decision remain + bound to the exact submitted revision. +4. **Promote.** Application intake, acceptance, deployment, availability, and launch authorization remain separate + facts. +5. **Discover.** Agents and the Programmable Explorer read digest-bound records from the discovery registry. -- [Architecture and trust boundaries](docs/ARCHITECTURE.md) -- [Discovery contract](docs/DISCOVERY_CONTRACT.md) -- [Review and promotion lifecycle](docs/REVIEW_LIFECYCLE.md) -- [Legacy intake migration](docs/MIGRATION.md) -- [Current code-maturity assessment](docs/CODE_MATURITY.md) -- [Open Review Standard](docs/OPEN_REVIEW_STANDARD.md) +Application content is untrusted data. The trusted intake workflow uses protected base code, read-only permissions, +bounded files, and no candidate execution. -## Apply +## Application intake -Use the released [Hookbuilder](https://github.com/0xprogrammable/hookbuilder). Your complete project stays in your own public GitHub repository. After exact -confirmation, the Builder opens a draft pull request containing exactly six generated files under -`submissions//`. +**Status: prelaunch.** Do not create an application pull request manually. -The Registry is in migration prelaunch until the matching Builder release activates this target. Existing applications -already opened against `0xprogrammable/programmable` keep their original review thread. +Once activated, Hookbuilder will open a draft pull request containing exactly six generated files under +`submissions//`. Existing applications remain on their original review threads. Read the +[migration contract](docs/MIGRATION.md) for the activation requirements. -## Verify +## Discovery registry -Node.js 20 or newer is required. The repository has no runtime dependencies. +Agents and integrations start with [`registry/index.json`](registry/index.json) or +[`registry/search-index.json`](registry/search-index.json) at one exact repository commit. A consumer fetches the +selected full record from that same commit and verifies its SHA-256 digest before use. -```bash -npm test -``` +Search results indicate relevance only. They do not prove originality, compatibility, acceptance, safety, deployment, +provider support, or availability. The statuses `design`, `candidate`, `accepted`, `deployed`, `available`, `suspended`, +and `retired` remain deliberately separate. + +Read the [discovery contract](docs/DISCOVERY_CONTRACT.md) before integrating. + +## Report a finding + +Reproducible false decisions, missing review rules, intake defects, identity mismatches, registry-integrity problems, +and documentation errors are useful findings. + +- [Report a non-sensitive checker or registry problem](https://github.com/0xprogrammable/apply/issues/new/choose). +- [Discuss an architecture or policy idea](https://github.com/0xprogrammable/apply/discussions). +- [Report an exploitable vulnerability privately](https://github.com/0xprogrammable/apply/security/advisories/new). + +Read [SECURITY.md](SECURITY.md) before testing or reporting a security-sensitive finding. Do not publish credentials, +wallet material, private repositories, personal data, or an unpatched exploit. + +## Documentation + +- [Architecture and trust boundaries](docs/ARCHITECTURE.md) +- [Open Review Standard](docs/OPEN_REVIEW_STANDARD.md) +- [Review and promotion lifecycle](docs/REVIEW_LIFECYCLE.md) +- [Discovery contract](docs/DISCOVERY_CONTRACT.md) +- [Code maturity assessment](docs/CODE_MATURITY.md) +- [Contributing](CONTRIBUTING.md) +- [Support](SUPPORT.md) + +## Related repositories + +- [Hookbuilder](https://github.com/0xprogrammable/hookbuilder) builds, checks, and prepares applications. +- [Programmable](https://github.com/0xprogrammable/programmable) contains the platform, contracts, and Explorer. -Application content is untrusted data. The `pull_request_target` intake job checks out only protected base code, uses -read-only permissions, hydrates only the bounded six-file package, and never executes candidate code. +## Independence -## Security and independence +Programmable Apply is independent open-source software. It does not claim affiliation with or endorsement by Uniswap +Labs or the Uniswap Foundation. -Read [SECURITY.md](SECURITY.md) before reporting a vulnerability. Programmable Registry is independent open-source -software. It does not claim affiliation with or endorsement by Uniswap Labs or Uniswap Foundation. +Released under the [MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md index e745c3c..65d79e3 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,14 +1,47 @@ # Security policy -Report vulnerabilities through GitHub private vulnerability reporting in this repository. Do not open a public issue -for an intake bypass, path-confusion defect, source-binding failure, registry-integrity problem, prompt-injection path, -credential exposure, or unpublished exploit. +## Report privately + +Report security-sensitive findings through [GitHub private vulnerability +reporting](https://github.com/0xprogrammable/apply/security/advisories/new). Do not open a public issue for an intake +bypass, path-confusion defect, source-binding failure, registry-integrity problem, prompt-injection path, credential +exposure, or unpublished exploit. Include the affected commit, files, minimal reproduction, impact, and preconditions. Never include real private keys, -seed phrases, access tokens, production secrets, or user funds. +seed phrases, access tokens, production secrets, personal data, or user funds. + +## In scope + +- the trusted application intake and its repository, revision, tree, and source binding; +- the public checker, policy, schemas, and decision integrity; +- generated registry records, indexes, history, and discovery boundaries; +- repository workflows and their permission boundaries; and +- the pinned Hookbuilder provenance receipt and vendored-byte verification. + +## Out of scope + +Applicant projects, Hookbuilder itself, Uniswap, wallets, RPC or infrastructure providers, the live Programmable +platform, deployed contracts, and third-party systems retain their own security processes. A weakness in one of those +systems is not automatically a vulnerability in Programmable Apply. + +## Responsible testing + +Test only in a local clone, a fork you control, or another environment containing synthetic data you control. Do not +test against production repositories, workflows, runners, registries, websites, contracts, wallets, providers, user +projects, or third-party systems without separate written authorization. + +Do not access, change, retain, or destroy data you do not own. Do not move funds, obtain credentials, submit malicious +applications, exhaust GitHub Actions or other resources, perform denial-of-service testing, use social engineering, or +publish an unpatched exploit. Stop testing and report privately if you encounter non-public data. + +## Safe harbor + +Research conducted in good faith and within this policy will be considered authorized for the limited purpose of this +policy. Programmable will not initiate legal action solely because of research that follows these rules. This does not +authorize activity against third parties or protect conduct outside this policy. If you are unsure whether a test is +permitted, ask through private vulnerability reporting before continuing. -The trusted intake validator, generated registry, schemas, GitHub workflows, vendored Builder receipt, and discovery -data boundary are in scope. Builder projects, Uniswap, wallets, providers, and the live Programmable platform retain -their own security processes. +## No bounty or guarantee -No response time, bounty, audit, safety, or remediation guarantee is implied. +This is not a standing bug bounty program. A report does not create an obligation to pay a reward or meet a response or +remediation deadline. No audit, safety, or remediation guarantee is implied. diff --git a/SUPPORT.md b/SUPPORT.md index 1db3adc..e9309cb 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,14 +1,18 @@ # Support -Use a GitHub issue for reproducible bugs, documentation problems, missing templates, agent-host compatibility, or a -proposal for a new capability pack. Include the Builder version, agent host, operating system, Node version, exact -command, sanitized output and a minimal public reproduction when possible. +Use the [issue chooser](https://github.com/0xprogrammable/apply/issues/new/choose) for reproducible checker defects, +review-rule gaps, intake failures, registry or schema problems, and documentation errors. Include the affected Apply +release or commit, exact command, sanitized output, and a minimal public reproduction when possible. -Use GitHub Discussions for architecture questions and unfamiliar product ideas when Discussions are enabled. Novelty is -not a security report and not a reason to force an idea into an existing template. +Use [Apply Discussions](https://github.com/0xprogrammable/apply/discussions) for architecture questions and unfamiliar +product ideas. Novelty is not a security report and not a reason to force an idea into an existing template. -Use private vulnerability reporting for security-sensitive findings. Do not post wallet material, credentials, private -repositories, personal data or unannounced vulnerabilities in public issues. +Use [Hookbuilder issues](https://github.com/0xprogrammable/hookbuilder/issues/new/choose) for installation, agent-host, +build, verification, template, or application-preparation support. + +Use [private vulnerability reporting](https://github.com/0xprogrammable/apply/security/advisories/new) for +security-sensitive findings. Do not post wallet material, credentials, private repositories, personal data, or +unannounced vulnerabilities in public issues. Project approval, deployment, provider routing, investment advice and guaranteed implementation support are not provided through repository issues. diff --git a/assets/social-preview.jpg b/assets/social-preview.jpg new file mode 100644 index 0000000..83efe37 Binary files /dev/null and b/assets/social-preview.jpg differ diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4dc117f..12f8dcc 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,6 @@ # Architecture -Programmable Registry separates four authorities that must not silently collapse into one another. +Programmable Apply separates four authorities that must not silently collapse into one another. 1. A builder-owned public repository is the source authority for a project. 2. A six-file application is bounded review data tied to one exact repository id, commit, tree, and evidence set. diff --git a/docs/CODE_MATURITY.md b/docs/CODE_MATURITY.md index 4e2f189..3057ace 100644 --- a/docs/CODE_MATURITY.md +++ b/docs/CODE_MATURITY.md @@ -7,7 +7,7 @@ self-assessment, not an independent audit. | --- | ---: | --- | --- | | Arithmetic and precision | 4 | Registry values use safe integers; the mandatory 10 bps identity is exact and tested | Economic correctness of submitted projects remains outside Registry arithmetic | | Auditing and observability | 3 | Exact source, record hashes, immutable history, deterministic review receipts, CI receipts, and public review threads | No independent Apply audit yet | -| Authentication and access control | 3 | Candidate identity binds to GitHub's immutable user id; intake authority is read-only | Remote branch protection must be verified after publication | +| Authentication and access control | 3 | Candidate identity binds to GitHub's immutable user id; intake authority is read-only; protected `main` checks are enforced | Initial acceptance authority remains one maintainer | | Complexity management | 3 | Closed schemas, bounded files, generated indexes, separate application and maintenance paths, and one small dependency-free public review engine | The vendored intake validator is intentionally large and needs continued differential testing | | Decentralization and governance | 1 | Decisions are public and append-only | Initial acceptance authority is one maintainer; no independent quorum is established | | Documentation | 4 | Architecture, discovery, open review rules, schemas, migration, contribution, support, and security contracts are explicit | Operational runbooks must stay synchronized with future website integration | @@ -15,5 +15,6 @@ self-assessment, not an independent audit. | Low-level and unsafe operations | 4 | Blobless bounded Git handling, disabled hooks/filters/submodules, byte/time/process limits, and no candidate execution under privileged CI | OS resource hard stops retain one Linux-only test path | | Testing and verification | 4 | Deterministic registry and decision tests plus the complete trusted intake adversarial suite | Hidden mutation corpora, production runner evidence, and an independent penetration review remain outstanding | -The practical release blockers are remote CI proof, protected-main enforcement, fresh-clone verification, and the -matching Builder activation. Local green checks alone do not prove those external states. +The repository release has public CI and protected-main evidence. New application intake remains in prelaunch until a +matching Hookbuilder release targets this repository and an end-to-end application canary passes against the released +contract. Local green checks alone do not prove those external states. diff --git a/docs/DISCOVERY_CONTRACT.md b/docs/DISCOVERY_CONTRACT.md index c740bbe..f056772 100644 --- a/docs/DISCOVERY_CONTRACT.md +++ b/docs/DISCOVERY_CONTRACT.md @@ -1,6 +1,6 @@ # Discovery contract -Agents and applications start with `registry/index.json` or `registry/search-index.json` at one exact Registry commit. +Agents and applications start with `registry/index.json` or `registry/search-index.json` at one exact Apply commit. They do not crawl project repositories or load every application into context. ## Required consumer behavior @@ -14,7 +14,7 @@ They do not crawl project repositories or load every application into context. 7. Preserve the record's exact status and limitations. `design`, `candidate`, `accepted`, `deployed`, `available`, `suspended`, and `retired` are distinct. Pending application -pull requests are not canonical records. An offline snapshot may be used only when clearly labeled with its Registry +pull requests are not canonical records. An offline snapshot may be used only when clearly labeled with its Apply commit and age; it must never be presented as live. ## Search behavior diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 881d74c..6908f93 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -1,7 +1,7 @@ # Legacy intake migration -The first Registry release starts in `prelaunch`. The released Builder continues to use its existing central target -until a matching Builder release activates this repository. +The first Apply release starts in `prelaunch`. The released Hookbuilder continues to use its existing central target +until a matching Hookbuilder release activates this repository. Application pull request `0xprogrammable/programmable#62` remains on its original review thread. It is recorded in `registry/config.json` as a continuing legacy pull request and is never silently copied, renumbered, closed, or claimed @@ -10,7 +10,7 @@ as accepted. A Builder status client may read that original thread with the Buil Activation requires all of the following: 1. this repository is public at the exact tested commit; -2. protected-branch checks are enforced; +2. the protected branch requires `Node 20`, `Node 22`, and `public-intake` before merge; 3. a released Hookbuilder version targets `0xprogrammable/apply`; 4. the vendored intake validator matches that Builder's application contract; and 5. `docs/builder/intake-status.json` and `registry/config.json` are changed together from `prelaunch` to `open`. diff --git a/docs/OPEN_REVIEW_STANDARD.md b/docs/OPEN_REVIEW_STANDARD.md index 1de8ce7..e0a9353 100644 --- a/docs/OPEN_REVIEW_STANDARD.md +++ b/docs/OPEN_REVIEW_STANDARD.md @@ -3,7 +3,8 @@ Programmable reviews exact project revisions. It does not rank ideas, judge whether a project is interesting, or reject unusual tokenomics merely because they are unusual. -The public standard has five decision-critical axes: +The public standard defines five decision-critical axes. A prepared review input records the evidence state for each +axis: 1. **Artifact identity** binds the repository, commit, tree, configuration and executable artifact. 2. **Functionality** checks that declared paths actually execute, including failure, recovery and no-market behavior. @@ -24,7 +25,8 @@ flowchart LR ``` The public checker ends at the unsigned review decision. It has no production credentials and cannot sign or issue a -launch permit. +launch permit. It validates a closed review input and applies the published policy; it does not fetch project +repositories, run project tests, or independently reproduce the supplied evidence. ## Decisions diff --git a/docs/builder/PUBLIC_GITHUB_PR_BETA.md b/docs/builder/PUBLIC_GITHUB_PR_BETA.md index f6b1c08..a1c0683 100644 --- a/docs/builder/PUBLIC_GITHUB_PR_BETA.md +++ b/docs/builder/PUBLIC_GITHUB_PR_BETA.md @@ -1,10 +1,10 @@ # Public GitHub application intake -The complete project stays in the builder-controlled public GitHub repository. A draft pull request to +The complete project stays in the applicant-owned public GitHub repository. A draft pull request to `0xprogrammable/apply:main` carries exactly six generated files under one `submissions//` directory. -The intake is `prelaunch` until a matching Programmable v4 Builder release activates this repository. Existing pull +The intake is `prelaunch` until a matching Hookbuilder release activates this repository. Existing pull requests already opened against `0xprogrammable/programmable` remain on that legacy review thread and are not silently moved or relabeled. diff --git a/scripts/test/verify-public-hook-application-workflow.test.mjs b/scripts/test/verify-public-hook-application-workflow.test.mjs index cb837f4..e321493 100644 --- a/scripts/test/verify-public-hook-application-workflow.test.mjs +++ b/scripts/test/verify-public-hook-application-workflow.test.mjs @@ -5,8 +5,10 @@ import test from "node:test"; const intake = fs.readFileSync(path.resolve(".github/workflows/verify-hook-builder.yml"), "utf8"); const ordinary = fs.readFileSync(path.resolve(".github/workflows/verify.yml"), "utf8"); +const postMerge = fs.readFileSync(path.resolve(".github/workflows/verify-post-merge.yml"), "utf8"); +const codeql = fs.readFileSync(path.resolve(".github/workflows/codeql.yml"), "utf8"); const validator = fs.readFileSync(path.resolve("scripts/verify-public-hook-application-core.mjs"), "utf8"); -const publicJob = intake.slice(intake.indexOf(" public-intake:"), intake.indexOf(" trusted-post-merge:")); +const publicJob = intake.slice(intake.indexOf(" public-intake:")); const verificationStep = publicJob.slice( publicJob.indexOf("- name: Verify closed public application package"), publicJob.indexOf("- name: Defer executable registry maintenance") @@ -18,6 +20,7 @@ const fetchStep = publicJob.slice( test("pull_request_target uses only protected base code and read-only authority", () => { assert.match(intake, /pull_request_target:\n\s+branches:\n\s+- main/u); + assert.doesNotMatch(intake, /\n push:|\n workflow_dispatch:/u); assert.match(intake, /\npermissions:\n contents: read\n/u); assert.doesNotMatch(intake, /secrets\.|contents:\s*write|pull-requests:\s*write|id-token:/u); assert.match(publicJob, /ref: \$\{\{ github\.event\.pull_request\.base\.sha \}\}/u); @@ -64,15 +67,25 @@ test("ordinary CI is read-only, credential-free, pinned, and covers Node 20 and assert.match(ordinary, /node:\n\s+- 20\n\s+- 22/u); assert.match(ordinary, /run: npm test/u); assert.doesNotMatch(ordinary, /secrets\.|github\.token|contents:\s*write/u); - for (const source of [intake, ordinary]) { + for (const source of [intake, ordinary, postMerge, codeql]) { const uses = [...source.matchAll(/^\s*uses:\s*([^\s#]+)/gmu)].map((match) => match[1]); assert.ok(uses.length >= 2); for (const action of uses) assert.match(action, /^[^@\s]+@[a-f0-9]{40}$/u); } }); +test("CodeQL is read-only apart from security result publication and uses pinned actions", () => { + assert.match(codeql, /\npermissions:\n contents: read\n security-events: write\n/u); + assert.match(codeql, /languages: javascript-typescript/u); + assert.match(codeql, /name: CodeQL/u); + assert.doesNotMatch(codeql, /secrets\.|contents:\s*write|pull-requests:\s*write/u); +}); + test("post-merge verifies the complete repository and every maintained submission", () => { - const postMerge = intake.slice(intake.indexOf(" trusted-post-merge:")); + assert.match(postMerge, /\n push:\n\s+branches:\n\s+- main/u); + assert.match(postMerge, /\n workflow_dispatch:/u); + assert.doesNotMatch(postMerge, /pull_request/u); + assert.match(postMerge, / trusted-post-merge:/u); assert.match(postMerge, /working-directory: source\n\s+run: npm test/u); assert.match(postMerge, /--verify-maintained/u); assert.match(postMerge, /--repository-root "\$source_root"/u); diff --git a/test/public-surface.test.mjs b/test/public-surface.test.mjs new file mode 100644 index 0000000..e02a1e0 --- /dev/null +++ b/test/public-surface.test.mjs @@ -0,0 +1,71 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import test from "node:test"; + +const root = path.resolve("."); +const read = (relative) => fs.readFileSync(path.join(root, relative), "utf8"); + +test("the public landing page states the checker and intake boundaries", () => { + const readme = read("README.md"); + assert.match(readme, /Public application intake is currently in prelaunch/u); + assert.match(readme, /does not fetch\nproject repositories, reproduce evidence, perform an audit/u); + assert.match(readme, /checkerOnly: true/u); + assert.match(readme, /launchAuthorized: false/u); + assert.ok(readme.indexOf("Public application intake is currently in prelaunch") < readme.indexOf("## How it works")); + assert.doesNotMatch(readme, /programmable-registry|programmable-v4-builder/u); +}); + +test("public support routes are canonical and have issue forms", () => { + const config = read(".github/ISSUE_TEMPLATE/config.yml"); + assert.match(config, /https:\/\/github\.com\/0xprogrammable\/apply\/security\/advisories\/new/u); + assert.match(config, /https:\/\/github\.com\/0xprogrammable\/hookbuilder\/issues\/new\/choose/u); + assert.doesNotMatch(config, /programmable-registry|programmable-v4-builder|hookbuilder\/discussions/u); + for (const form of ["review-or-registry-bug.yml", "documentation.yml"]) { + assert.equal(fs.existsSync(path.join(root, ".github/ISSUE_TEMPLATE", form)), true); + } +}); + +test("the security policy separates private reports, testing limits, and rewards", () => { + const security = read("SECURITY.md"); + assert.match(security, /## Report privately/u); + assert.match(security, /## Responsible testing/u); + assert.match(security, /## Safe harbor/u); + assert.match(security, /This is not a standing bug bounty program/u); +}); + +test("contribution paths and the pull request template stay in sync", () => { + const contributing = read("CONTRIBUTING.md"); + const template = read(".github/PULL_REQUEST_TEMPLATE.md"); + assert.match(contributing, /three intentionally separate contribution paths/u); + assert.match(template, /Generated six-file application package/u); + assert.match(template, /Apply repository maintenance/u); + assert.match(template, /Open Review Standard maintenance/u); +}); + +test("public Markdown does not contain a broken relative link", () => { + const queue = [root]; + const markdown = []; + while (queue.length > 0) { + const directory = queue.pop(); + for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { + const absolute = path.join(directory, entry.name); + const relative = path.relative(root, absolute); + if (entry.isDirectory()) { + if (![".git", "node_modules", "vendor"].includes(entry.name)) queue.push(absolute); + } else if (entry.isFile() && relative.endsWith(".md")) { + markdown.push(relative); + } + } + } + + for (const relative of markdown.sort()) { + const source = read(relative); + for (const match of source.matchAll(/!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/gu)) { + const target = match[1]; + if (/^(?:https?:|mailto:|#)/u.test(target)) continue; + const pathname = decodeURIComponent(target.split("#", 1)[0]); + assert.equal(fs.existsSync(path.resolve(root, path.dirname(relative), pathname)), true, `${relative}: ${target}`); + } + } +});