-
Notifications
You must be signed in to change notification settings - Fork 93
feat(tools/forgejo): add Forgejo/Gitea adapter bridge (part of #310) #1469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
| <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
| **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* | ||
|
|
||
| - [`tools/forgejo/`](#toolsforgejo) | ||
| - [Prerequisites](#prerequisites) | ||
| - [Configuration](#configuration) | ||
|
|
||
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
|
||
| <!-- SPDX-License-Identifier: Apache-2.0 | ||
| https://www.apache.org/licenses/LICENSE-2.0 --> | ||
|
|
||
| # `tools/forgejo/` | ||
|
|
||
| **Capability:** contract:tracker + contract:source-control + contract:change-request | ||
|
potiuk marked this conversation as resolved.
|
||
|
|
||
| **Coverage:** partial | ||
|
|
||
| **Kind:** implementation | ||
|
|
||
| **Vendor:** Forgejo / Gitea | ||
|
|
||
| Forgejo / Gitea REST substrate. Pure read/write wrapper used by every lifecycle phase (triage / intake / fix / resolve / stats). See [`tool.md`](tool.md) for the operation catalogue and the per-area files ([`issue-template.md`](issue-template.md), [`labels.md`](labels.md), [`operations.md`](operations.md), [`project-board.md`](project-board.md), [`status-rollup.md`](status-rollup.md)) for specifics. | ||
|
|
||
| This tool implements three capability contracts: `contract:tracker` (issues / labels), `contract:source-control` (Git branch / commit / diff / push, documented in [`source-control.md`](source-control.md)), and `contract:change-request` — partial pull-request recipes driven by `tea pr` and REST endpoints. On Forgejo/Gitea the `change-request` `land` verb resolves to `tea pr merge` (the forge lands and closes atomically). | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Runtime:** Bash — this is a doc-only adapter; skills invoke the `tea` CLI (`tea`) and `git`, no local package. | ||
| - **CLIs:** `tea` (authenticated), `git` (source-control capability), `curl`, `jq`. | ||
| - **Credentials / auth:** Every REST recipe in [`operations.md`](operations.md) (collaborator lookup, issue create, issue body edit, comments, PR create) sends `Authorization: token $TEA_TOKEN` to `$FORGEJO_HOST`, so both variables are required whenever those recipes run. The token value is stored in a private configuration file in the user's home directory (e.g. `~/.config/tea/token` or `~/.config/apache-magpie/user.md` per [`AGENTS.md` § Local setup](../../AGENTS.md#local-setup)) and exported to the agent's environment. `$FORGEJO_HOST` is the base URL including the scheme (`https://forge.example.org`), since the recipes build `$FORGEJO_HOST/api/v1/...` from it. For `tea` CLI operations, `tea login list` must show an authenticated login. | ||
| - **Network:** The Forgejo/Gitea instance host (`$FORGEJO_HOST`) must be added to the sandbox network allowlist, permitting access to the instance API (`/api/v1/`) and Git remote; source-control recipes are offline except explicit `fetch` / `push`. | ||
|
|
||
| ## Configuration | ||
|
|
||
| Adopters select Forgejo-backed tracker, source-control, and change-request behavior through `<project-config>/project.md` repository keys such as `tracker_repo`, `upstream_repo`, and the source-control / change-request entries in the *Tools enabled* table. Forgejo issue body fields, labels, and PR-management knobs live in the matching `<project-config>/*-config.md` files documented from `projects/_template/README.md`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| <!-- SPDX-License-Identifier: Apache-2.0 | ||
| https://www.apache.org/licenses/LICENSE-2.0 --> | ||
|
|
||
| <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
| <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
| **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* | ||
|
|
||
| - [Forgejo / Gitea — issue-body field schema](#forgejo--gitea--issue-body-field-schema) | ||
| - [Where the schema is authoritative](#where-the-schema-is-authoritative) | ||
| - [Field roles the skills use](#field-roles-the-skills-use) | ||
| - [Body-field surgery](#body-field-surgery) | ||
| - [Empty-field convention](#empty-field-convention) | ||
| - [Issue-template to CVE 5.x mapping](#issue-template-to-cve-5x-mapping) | ||
|
|
||
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
|
||
| # Forgejo / Gitea — issue-body field schema | ||
|
|
||
| The skills treat every tracker's **issue body** as a structured | ||
| document with named fields, rather than free-form prose. Each field is | ||
| a markdown `### <field name>` heading followed by a value block; the | ||
| set of field names is the schema the skills read from and write to. | ||
|
|
||
| The field names themselves are project-specific (they come from the | ||
| project's Forgejo issue-template configuration). Generic skill logic refers to | ||
| them by **role** — *"the CVE-tool-link field"*, *"the public-advisory | ||
| URL field"* — and the role → concrete-name mapping is declared in the | ||
| project manifest. For an adopting project, see | ||
| [`../../<project-config>/project.md`](../../<project-config>/project.md#issue-template-fields). | ||
|
|
||
| ## Where the schema is authoritative | ||
|
|
||
| Three surfaces need to stay in lock-step whenever a field is added, | ||
| renamed, or removed: | ||
|
|
||
| 1. **The Forgejo Template** — `.gitea/ISSUE_TEMPLATE/issue_report.yaml` (or equivalent `.forgejo/`) | ||
| in the tracker repo. This is what Forgejo renders as the "New | ||
| issue" form and is the machine-readable schema. | ||
| 2. **The project manifest** — `<project-config>/project.md` declares | ||
| the concrete field name each skill role maps to. Renaming the | ||
| field in the YAML requires updating this mapping. | ||
| 3. **The skills that write fresh issue bodies** — `security-issue-import` | ||
| emits a heredoc body with the full field set; when the schema | ||
| changes, the heredoc must change in lock-step. | ||
|
|
||
| No skill parses the YAML at runtime. The field list is hand- | ||
| maintained in the project manifest and in the `security-issue-import` | ||
| heredoc, and the three surfaces are kept aligned by convention. | ||
|
|
||
| ## Field roles the skills use | ||
|
|
||
| The generic lifecycle refers to fields by these roles: | ||
|
|
||
| | Role | Read by | Written by | Purpose | | ||
| |---|---|---|---| | ||
| | `issue-description` | dedupe | import | The verbatim inbound report; private to the security team. | | ||
| | `public-summary` | CVE JSON generator | release manager (Step 13) | Sanitised one-paragraph public summary for the advisory. | | ||
| | `affected-versions` | CVE JSON generator, sync | sync proposes, user confirms | The `>= X, < Y` range that populates CVE 5.x `affected[]`. | | ||
| | `security-thread` | dedupe, sync (reporter-notification lookup) | import | Private pointer to the inbound mail thread — the Gmail `threadId`, any PonyMail archive URL, and the root `Message-ID` (archive-independent message handle; backtick-wrapped). **Never** exported to the public CVE record. | | ||
| | `public-advisory-url` | CVE JSON generator, sync (gates close) | sync (Step 14) | Public archive URL; tagged `vendor-advisory` in `references[]`. | | ||
| | `reporter-credit` | CVE JSON generator | import (placeholder), sync (after reporter confirms) | Credit line as the reporter wants to appear in the public advisory. | | ||
| | `pr-with-fix` | sync, CVE JSON generator | fix, sync | URL of the merged `<upstream>` PR. | | ||
| | `remediation-developer` | CVE JSON generator | sync (auto-populated from `pr-with-fix` author when set; manual edits preserved) | Person(s) who authored the fix; one credit per line. | | ||
| | `cwe` | CVE JSON generator | sync proposes, user confirms | CWE number for the CVE 5.x `problemTypes[]`. | | ||
| | `severity` | CVE JSON generator | sync proposes, user confirms | CVSS severity; never copy the reporter's self-assigned value. | | ||
| | `cve-tool-link` | sync, security-cve-allocate (blocker check) | security-cve-allocate | Canonical link to the CVE record in the project's CVE tool. | | ||
|
|
||
| The concrete field names each role maps to for the adopting project | ||
| live in the project manifest. | ||
|
|
||
| ## Body-field surgery | ||
|
|
||
| Skills that update one field without touching the rest use the | ||
| following pattern: | ||
|
|
||
| 1. **Read** the full body (`curl -fsS -H "Authorization: token $TEA_TOKEN" "$FORGEJO_HOST/api/v1/repos/<tracker>/issues/<N>" | jq -r .body` or `tea issues <N> --repo <tracker> --output json | jq -r .body`). | ||
| 2. **Split** on `\n### ` to get per-field sections. | ||
| 3. **Replace** the target section's value (between its `### <name>\n\n` | ||
| header and the next `### ` or end-of-body). | ||
| 4. **Join** the sections back together. | ||
| 5. **Write** the new body via the REST API PATCH endpoint (`curl -fsS -X PATCH -H "Authorization: token $TEA_TOKEN" -H "Content-Type: application/json" --data-binary @<scratch>/issue-body.json "$FORGEJO_HOST/api/v1/repos/<tracker>/issues/<N>"` with the payload formatted via the Write tool per [`operations.md`](operations.md#edit--body)). | ||
|
|
||
| Never construct the body by string concatenation in a shell command — | ||
| literal backticks, `$(…)`, and newlines in the body are silently | ||
| corrupted by shell quoting. Always materialise the edited body to a | ||
| temp file first. | ||
|
|
||
| ## Empty-field convention | ||
|
|
||
| Forgejo's issue-form renderer behaves similarly to GitHub's. The skills honour this convention: | ||
|
|
||
| - On **read**, treat `_No response_` as "field unset". | ||
| - On **write**, preserve `_No response_` in fields the triager has | ||
| not yet filled (do not collapse them to empty strings or delete | ||
| the heading). | ||
| - The CVE JSON generator treats `_No response_` as absence and simply | ||
| omits the corresponding CVE-record element. | ||
|
|
||
| ## Issue-template to CVE 5.x mapping | ||
|
|
||
| The `generate-cve-json` tool maps body-field roles to CVE 5.x record | ||
| elements as follows (generic — applies to any project using this | ||
| schema): | ||
|
|
||
| | Body field role | CVE 5.x element | | ||
| |---|---| | ||
| | `public-summary` | `descriptions[].value` | | ||
| | `affected-versions` | `affected[].versions[].version` / `.lessThan` | | ||
| | `cwe` | `problemTypes[].descriptions[].cweId` | | ||
| | `severity` | `metrics[].other.content` (textual severity) | | ||
| | `public-advisory-url` | `references[]` with `tags: ["vendor-advisory"]` | | ||
| | `pr-with-fix` | `references[]` with `tags: ["patch"]` | | ||
| | `reporter-credit` | `credits[]` with `type: "finder"` | | ||
| | `remediation-developer` | `credits[]` with `type: "remediation developer"` | | ||
| | `security-thread` | **not exported** — private-only | | ||
| | `cve-tool-link` | **not exported** — points at the tool itself, not at a public URL | |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.