Add credential preflight, categorized errors and operations guides
Sync workflow: every failure is now reported as `ERROR: [category] message` with the categories configuration, credentials (HTTP 401), permissions (HTTP 403) and api (other HTTP errors, unreachable service); HTTP 404 is a configuration error. Before changing anything the workflow checks that the GitHub token can administer the mirror repository and stops with a permissions error otherwise. No secret value is printed. Guides: onboarding (with runner labels, prerequisites and offline runner symptoms), credentials (minimum permissions, preflight, rotation) and troubleshooting (every message mapped to a category and a fix). README capability table updated. MIL-002 records the verification of scoped workflow support: Gitea 1.27.3 runs the workflow in this repository; delivery to other repositories is not yet verified. Task: MIL-002#2 Task: MIL-002#3 Task: MIL-002#4 Task: MIL-002#5 Task: MIL-002#6 Task: MIL-002#7 Refs #9 Refs #10 Refs #11 Refs #12 Refs #13 Refs #14 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# Workflow credentials
|
||||
|
||||
The sync workflow uses two secrets. Give each the least privilege that works,
|
||||
store it only as a Gitea secret, and rotate it when a person with access
|
||||
leaves.
|
||||
|
||||
| Secret | Content | Used for |
|
||||
| --- | --- | --- |
|
||||
| `TOKEN_FOR_GITEA` | A bare token, a JSON string, or JSON with `GITEA_TOKEN` | Reading the repository (description, topics) and its push mirrors |
|
||||
| `CREDENTIALS_FOR_GITHUB` | JSON object with a non-empty `GITHUB_PAT` | Changing the description and topics of the GitHub mirror |
|
||||
|
||||
## Minimum permissions
|
||||
|
||||
These come from the Gitea and GitHub documentation and the API calls the
|
||||
workflow makes. They have **not been confirmed with a minimal token on this
|
||||
instance yet**; S05 should confirm them when the tokens are created.
|
||||
|
||||
**Gitea token** (a personal access token of a user, not a deploy key; deploy
|
||||
keys do not work for the REST API):
|
||||
|
||||
- scope `read:repository`
|
||||
- the user must be allowed to read the repository's push mirrors, which
|
||||
Gitea limits to repository administrators
|
||||
|
||||
Calls made: `GET /repos/{owner}/{repo}` and `GET /repos/{owner}/{repo}/push_mirrors`.
|
||||
|
||||
**GitHub token** (fine-grained personal access token):
|
||||
|
||||
- Resource owner: the owner of the mirror repository
|
||||
- Repository access: only the mirror repository
|
||||
- Repository permission: **Administration: Read and write** (no other permission)
|
||||
- Set an expiry date
|
||||
|
||||
Calls made: `GET /repos/{owner}/{repo}`, `PATCH /repos/{owner}/{repo}` (description)
|
||||
and `PUT /repos/{owner}/{repo}/topics`.
|
||||
|
||||
Format of `CREDENTIALS_FOR_GITHUB`:
|
||||
|
||||
```json
|
||||
{"GITHUB_PAT": "<token>"}
|
||||
```
|
||||
|
||||
## What the workflow checks before it changes anything
|
||||
|
||||
The workflow runs a preflight and writes nothing to GitHub unless it passes:
|
||||
|
||||
1. Both secrets exist and have the expected shape.
|
||||
2. Gitea accepts the token and the repository is visible with it.
|
||||
3. Exactly one GitHub push mirror is configured.
|
||||
4. GitHub accepts the token for the mirror repository **and** the token
|
||||
reports administration access to it.
|
||||
|
||||
On success the log says `Preflight passed: Gitea and GitHub accepted the
|
||||
credentials.` Failures start with a category such as `[credentials]` or
|
||||
`[permissions]`; see [troubleshooting.md](troubleshooting.md). No secret value
|
||||
is ever printed.
|
||||
|
||||
## Rotating a token
|
||||
|
||||
1. Create the new token with the permissions above.
|
||||
2. Replace the secret value in the repository or organization settings.
|
||||
3. Run the workflow manually and wait for `Preflight passed`.
|
||||
4. Revoke the old token.
|
||||
@@ -0,0 +1,71 @@
|
||||
# Onboarding a repository
|
||||
|
||||
How a DevOps professional makes a TirSystem repository use the shared
|
||||
**Sync GitHub mirror metadata** workflow, and which runners it needs. Only
|
||||
this workflow exists today; the quality-check and release workflows are
|
||||
planned (see the [Project Plan](../docs/project-plan.md)).
|
||||
|
||||
## What has been verified
|
||||
|
||||
| Item | Status |
|
||||
| --- | --- |
|
||||
| Gitea version | 1.27.3 |
|
||||
| `.gitea/scoped_workflows/sync-github-metadata.yml` runs in this repository | Verified: run 16, `workflow_dispatch`, succeeded |
|
||||
| The same workflow applies to other repositories automatically | **Not verified.** Confirm how scoped workflows are delivered on the instance (admin or organization settings) before relying on it. |
|
||||
|
||||
Until delivery is verified, onboard a repository by copying the workflow (below).
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Check the prerequisites** in the repository: Actions are enabled, and a
|
||||
runner with the label `ubuntu-latest` and `python3` is online (see
|
||||
[Runners](#runners)).
|
||||
2. **Configure exactly one GitHub push mirror** in the repository settings
|
||||
(Settings, Repository, Mirror settings, Push mirror). The workflow fails
|
||||
when there are zero or several GitHub mirrors.
|
||||
3. **Add the two secrets** in the repository (or organization) settings,
|
||||
using the scopes in [credentials.md](credentials.md):
|
||||
- `TOKEN_FOR_GITEA`
|
||||
- `CREDENTIALS_FOR_GITHUB` (JSON with `GITHUB_PAT`)
|
||||
4. **Deliver the workflow:**
|
||||
- *If scoped workflows apply to the repository:* nothing to copy.
|
||||
- *Otherwise:* copy `.gitea/scoped_workflows/sync-github-metadata.yml`
|
||||
from this repository to `.gitea/workflows/` in the target repository.
|
||||
Pin the copy to a reviewed version of this repository and re-copy
|
||||
when it changes.
|
||||
5. **Set a description and topics** on the Gitea repository, so there is
|
||||
something to sync.
|
||||
6. **Run it once manually:** Actions, **Sync GitHub mirror metadata**,
|
||||
Run workflow. The log must end with `Synced description and topics to
|
||||
<owner>/<repo>.` and the GitHub repository must show the same description
|
||||
and topics.
|
||||
7. If it fails, use [troubleshooting.md](troubleshooting.md).
|
||||
|
||||
## Runners
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Label the workflow uses | `ubuntu-latest` |
|
||||
| Labels offered by the runner on this instance | `ubuntu-latest`, `ubuntu-24.04`, `ubuntu-22.04` |
|
||||
| Tools the workflow needs | `python3` (standard library only), outbound HTTPS to the Gitea API and `api.github.com` |
|
||||
| Needed for `actions/checkout` (used by the validation workflow) | `git` and Node.js, normally in the runner image |
|
||||
|
||||
**Check that a suitable runner is online** (needs permission to view runners):
|
||||
|
||||
```bash
|
||||
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
||||
https://git.tirsystem.com/api/v1/repos/<owner>/<repo>/actions/runners
|
||||
```
|
||||
|
||||
For runners shared by the whole instance, an administrator uses
|
||||
`/api/v1/admin/actions/runners`. At the time of writing the repository and
|
||||
organization lists are empty and one instance-level runner (`36cd20104923`)
|
||||
is `online`.
|
||||
|
||||
**Offline or incompatible runner**
|
||||
|
||||
| Symptom | Likely cause | Action |
|
||||
| --- | --- | --- |
|
||||
| Run stays `waiting` | No online runner has the label in `runs-on` | Start the runner, or register one with the label |
|
||||
| Job fails at the start with a missing command | Runner image lacks `python3`, `git` or Node.js | Use an image that has them |
|
||||
| Job cannot reach the API | Runner has no outbound HTTPS | Fix runner network or proxy settings |
|
||||
@@ -0,0 +1,60 @@
|
||||
# Diagnosing a failed run
|
||||
|
||||
Open the run in Gitea (Actions) and read the last lines of the failing step.
|
||||
Every failure from the sync script is written as
|
||||
|
||||
```
|
||||
ERROR: [<category>] <message>
|
||||
```
|
||||
|
||||
The category tells you where to look. A failure outside the script (the job
|
||||
never starts, or stops before the step) is a **runner** problem.
|
||||
|
||||
| Category | Meaning | First thing to check |
|
||||
| --- | --- | --- |
|
||||
| `configuration` | A secret or a repository setting is missing or malformed | Secret names and format, push mirror setup |
|
||||
| `credentials` | A service rejected the token (HTTP 401) | Token expired, revoked or mistyped |
|
||||
| `permissions` | The token is valid but not allowed (HTTP 403, or no GitHub administration access) | Token scopes and repository access |
|
||||
| `api` | Another HTTP error, or the service was unreachable | Service status, runner network |
|
||||
| runner | No `ERROR:` line; the run waits, or the job fails before the script | Runner online, label, tools |
|
||||
|
||||
## Messages and fixes
|
||||
|
||||
| Message (start) | Category | Cause and fix |
|
||||
| --- | --- | --- |
|
||||
| `CREDENTIALS_FOR_GITHUB is missing or empty.` | configuration | Add the secret |
|
||||
| `CREDENTIALS_FOR_GITHUB must contain valid JSON.` | configuration | The value must be JSON such as `{"GITHUB_PAT": "..."}` |
|
||||
| `CREDENTIALS_FOR_GITHUB must be a JSON object.` | configuration | Use an object, not a list or string |
|
||||
| `CREDENTIALS_FOR_GITHUB must contain a non-empty GITHUB_PAT.` | configuration | Add the `GITHUB_PAT` key with a token |
|
||||
| `TOKEN_FOR_GITEA is missing or empty.` | configuration | Add the secret |
|
||||
| `TOKEN_FOR_GITEA must contain a non-empty GITEA_TOKEN.` | configuration | The JSON form needs a `GITEA_TOKEN` key |
|
||||
| `Could not determine the Gitea source repository.` | configuration | The run has no repository name; report as a defect |
|
||||
| `Expected exactly one GitHub push mirror ... found 0` | configuration | Add a GitHub push mirror in the repository settings |
|
||||
| `Expected exactly one GitHub push mirror ... found N` | configuration | Keep one GitHub push mirror |
|
||||
| `Could not determine the GitHub owner and repository ...` | configuration | The mirror address must look like `https://github.com/<owner>/<repo>.git` |
|
||||
| `Gitea API request failed with HTTP 401` | credentials | Create a new Gitea token and update `TOKEN_FOR_GITEA` |
|
||||
| `GitHub API request failed with HTTP 401` | credentials | Create a new GitHub token and update `CREDENTIALS_FOR_GITHUB` |
|
||||
| `... HTTP 403 ...` (Gitea) | permissions | Token needs `read:repository`, and its user needs administrator access to the repository |
|
||||
| `... HTTP 403 ...` (GitHub) | permissions | Token needs Administration read and write on the mirror repository |
|
||||
| `The GitHub token cannot administer <repo>` | permissions | Same as above; the token can read the repository but not edit it |
|
||||
| `... HTTP 404 ...` | configuration | Repository not found, or the token cannot see it; check the mirror address and token repository access |
|
||||
| `... HTTP 5xx ...` | api | Service problem; re-run later |
|
||||
| `... API is unreachable ...` | api | Network, DNS or proxy problem on the runner |
|
||||
|
||||
## Not an error
|
||||
|
||||
`WARNING: Gitea returned an invalid push mirror list; GitHub metadata was not
|
||||
synced.` The run succeeds but nothing was synced. Check that the Gitea
|
||||
version supports the push mirror API and re-run.
|
||||
|
||||
## Runner problems
|
||||
|
||||
See the [Runners](onboarding.md#runners) section. In short: if the run stays
|
||||
`waiting`, no online runner has the label; if the job fails before the
|
||||
script, the runner image is missing a tool.
|
||||
|
||||
## Re-running
|
||||
|
||||
Use **Run workflow** (`workflow_dispatch`) after fixing the cause. The sync is
|
||||
safe to repeat: it overwrites the GitHub description and topics with the
|
||||
Gitea values.
|
||||
Reference in New Issue
Block a user