Skip to main content

sandbox-test

Test a change to the .asf.yaml parser against a real GitHub repository, using the "Test a change against the sandbox repo" workflow. Covers one pull request, a local branch, or a batch of open PRs. Builds a set/update/unset test matrix, runs it noop then live, verifies every claim by reading the GitHub API back, resets the sandbox, and then proposes a review comment and a disposition for the human to approve. Invoke when asked to "sandbox-test this", "test PR NNN against the sandbox", "does this actually work on GitHub", "test the open PRs", or before approving or merging any PR that touches asfyaml/feature/.

Informações da origem

Repositório
apache/infrastructure-asfyaml
Última atividade na origem
24 de outubro de 2026 às 09:54
Idioma detectado do SKILL.md
inglês
Estrelas
16
Forks
27

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
sandbox-test
description
Test a change to the .asf.yaml parser against a real GitHub repository, using the "Test a change against the sandbox repo" workflow. Covers one pull request, a local branch, or a batch of open PRs. Builds a set/update/unset test matrix, runs it noop then live, verifies every claim by reading the GitHub API back, resets the sandbox, and then proposes a review comment and a disposition for the human to approve. Invoke when asked to "sandbox-test this", "test PR NNN against the sandbox", "does this actually work on GitHub", "test the open PRs", or before approving or merging any PR that touches asfyaml/feature/.
# Testing a parser change against a sandbox repo Unit tests prove a feature parses its YAML and calls the API it meant to call. They do not prove GitHub accepts the call, or that the result is the one the contributor had in mind. Three of the bugs this skill exists to catch passed their unit tests and exited 0 while changing nothing on GitHub. [docs/testing-a-change.md](../../../docs/testing-a-change.md) is the reference for the workflow itself. This skill is the procedure to run around it. ## The rule that matters most **A green run is not a result. Reading the setting back from the GitHub API is the result.** The parser can print "Setting X to Y", exit 0, and have changed nothing — that is exactly what a broken state check looks like. Every claim you make must trace to an API response you read after the run, not to a log line and not to an exit code. ## Safety - **Never point `asfyaml-run` at a directory named after a real project.** The parser derives the target repository from the directory name, so `--repo /tmp/airflow` acts on `apache/airflow`. The sandbox directory must be named after the sandbox repo. - **Read the diff before you dispatch.** Dispatching executes the PR's code with a token holding admin rights on the sandbox. For a PR from a fork that is code from outside the project, and the person dispatching is the security control. Read it, and check the commit SHA in the run summary matches what you read. - **Never dispatch someone else's PR against the Apache sandbox to "see what happens".** Self-test in your own fork first; it spends your minutes and your sandbox. ## 1. Pick a sandbox | | Your own fork | `apache/infrastructure-asfyaml` | |---|---|---| | Who runs it | any contributor | committer or infra admin | | Sandbox | `<you>/infrastructure-asfyaml-sandbox` | `apache/infrastructure-asfyaml-sandbox` | | Token | one you make | the one infra installed | | Ref input | `ref` = your branch | `pr` = the PR number | | Setup | below, once | already done | The sandbox defaults to the sandbox repo of whoever owns the repo the workflow runs in, so a fork run cannot reach the Apache sandbox. **Prefer your own fork.** Use the Apache sandbox only when the feature cannot work anywhere else — some settings are org-only. Merge queue rules, for example, are rejected outright on a user-owned repository, and no amount of parser fixing changes that. ### One-time setup in your own fork 1. Enable Actions on the fork (GitHub disables them on new forks). 2. Create `<you>/infrastructure-asfyaml-sandbox`, public, with a small baseline `.asf.yaml` on `main`. Keep a `baseline` branch pointing at that commit — resetting is then one push. 3. Create an environment named exactly `sandbox` in the fork. 4. Add secret `ASFYAML_SANDBOX_TOKEN` to that environment: a fine-grained PAT whose **repository access is only the sandbox repo**. Token permissions, by what you are testing: | Feature under test | Permission | |---|---| | most repository settings, rulesets, autolinks, interaction limits, branch protection | `Administration: Read and write` | | deployment environments | `Environments: Read and write` | | Pages | `Pages: Read and write` | | `oidc_subject` (Actions OIDC subject claim) | `Actions: Read and write` | | pushing test branches to the sandbox | `Contents: Read and write` | A 403 saying `Resource not accessible by personal access token` almost always means the token's *repository access list* is wrong, not its permission level — check which repo it was granted before re-reading the permission checkboxes. ## 2. Preflight the branch Do all of this before dispatching anything. 1. **Check the branch can run at all.** The workflow calls `asfyaml-run --branch ...`, and that flag arrived with the sandbox workflow itself. Any branch cut before then dies with `unrecognized arguments: --branch`: ```bash git show <ref>:asfyaml/cli.py | grep -q -- '--branch' || echo "needs rebase onto main" ``` 2. **Rebase onto current `main` if needed.** For someone else's PR, push the rebase to a branch in *your* fork (`sandbox-test/pr-<NNN>`) — never to the contributor's branch. 3. **Run the suite and the hooks** on the rebased tree: `poetry run pytest` and `poetry run pre-commit run --all-files`. Report what you ran, not what you assume. 4. **Read the diff of the directive**, both for the security reason above and because you cannot design a test matrix for code you have not read. ## 3. Build the test matrix A single "does it turn on" run is not a test of a directive. Most `.asf.yaml` directives are declarative, so the interesting behaviour is at the edges. Cover every row that applies: | Case | Config | What it proves | |---|---|---| | **Set** | key present, feature off beforehand | the enable path works | | **Update** | key present with a *different* value | the change path works, not just create | | **Idempotent re-apply** | same config twice | no redundant write on the second run | | **Unset (explicit)** | `enabled: false`, feature **on** beforehand | the disable path works | | **Unset (removal)** | key deleted, feature **on** beforehand | removal disables what the file used to manage | | **Unmanaged** | key never present, feature **on** beforehand | the directive leaves alone what it does not manage | | **No match / negative** | something the config should *not* touch | scoping is right | Rules for building it: - **Choose values that cannot be confused with the starting state.** If the setting is already `5`, test with `7`. A test whose pass state equals its start state proves nothing. - **Seed the "before" state deliberately.** For the unset and unmanaged rows the feature must be *on* before the run, otherwise a no-op looks like a success. Set it by hand through the API first. - **Seed things the directive must not touch.** An unrelated autolink, a branch that matches no pattern, a ruleset the config does not mention. ### The two traps that make an edge case silently untestable **`github:` directives only run on the default branch.** `feature/github/__init__.py` returns early unless the branch being processed equals the repository's default branch, and in a workflow checkout that resolves to `main`. So `sandbox_branch: test/pr-42` makes every `github:` directive a no-op and the run still goes green. **Put the test config on the sandbox's `main`** and reset afterwards. The workflow warns when `sandbox_branch` is anything else; treat that warning as "this run proved nothing", not as a style note. **`previous_yaml` is empty in every sandbox and CI run.** It is read from a cache at `/x1/asfyaml`, which exists only in production. Any directive branch guarded by "was this key in the previous `.asf.yaml`" cannot be exercised here — say so rather than claiming coverage. That second trap is also a recurring *bug* source, so check for this shape while reading the diff: ```python if not enabled and not was_previously_configured: return ``` It means an explicit `false` cannot turn off a setting that is currently on, whenever the cache is cold or the setting was enabled outside `.asf.yaml`. It has been found in more than one directive. Test the **unset (explicit)** row specifically to catch it. ## 4. Run it 1. Record the before state from the API, in full, for everything the run should and should not touch. 2. Dispatch with `noop: true`. Read the whole apply step — `grep` with a tight `tail` will truncate the interesting lines. Check it names every change you expect. 3. Dispatch with `noop: false`. 4. **Read the state back from the API.** Compare against the before state field by field. 5. Repeat per matrix row, resetting in between when a row needs a different start state. Some settings take time to settle — CodeQL default setup reports `languages: []` until its setup workflow finishes. If a field looks wrong immediately after a write, wait for any triggered run in the sandbox to complete and read again before calling it a bug. ### When a run fails, find out whose fault it is Before attributing a failure to the PR, **send the same request to GitHub yourself**, by hand, bypassing the parser: ```bash gh api -X POST repos/<you>/infrastructure-asfyaml-sandbox/<endpoint> --input payload.json ``` If a hand-written payload fails identically, the parser is not the problem — the feature is unavailable in this environment, and the PR needs an org-owned sandbox. If it succeeds, the parser's payload is wrong and you have the diff to prove it. Also probe the endpoint's *read* semantics: several GitHub endpoints return `200` with a body field rather than the `404`-means-off behaviour a directive might assume. ## 5. Reset the sandbox Leaving state behind makes the next run's result ambiguous. Undo everything: - push `baseline` over `main` (`git push origin baseline:main --force`) - delete created rulesets, autolinks, environments, branch protections and test branches - turn off anything the baseline cannot turn off — the parser may be unable to disable what it enabled, which is precisely one of the bugs being hunted - confirm the reset by reading the API, the same way you confirmed the change ## 6. Propose a comment Draft it, show it, **wait for explicit approval, then post**. Never post unprompted. A good comment contains: - what was tested, at which **commit SHA**, against which sandbox, with **run links** - a before/after table of actual API values, not prose - whether the branch needed a rebase to run at all - which matrix rows could **not** be covered, and why (the cache, org-only features) - findings, each with the evidence that supports it and a concrete suggested fix State plainly when a failure is not the PR's fault. "GitHub rejects this identically for a hand-written payload" saves the author a day. ## 7. Propose a disposition Recommend one, with the reasoning, and let the human decide: | Disposition | When | |---|---| | **Approve** | matrix passes, docs updated, tests present | | **Approve with follow-up** | works, but a non-blocking gap worth an issue | | **Request changes** | a matrix row fails, or a finding needs a code change | | **Needs committer run** | blocked only by a limitation of a personal sandbox | | **Needs author input** | the premise did not reproduce; ask before judging | Remember a schema change is a documentation change: a directive not described in `README.md` is not finished. ### Merging Merge only when **all** of these hold: 1. the human explicitly approved the merge in this session, 2. they have merge permission on `apache/infrastructure-asfyaml`, 3. the sandbox result was verified by reading the API, not by a green run, 4. CI is green on the head commit you tested, and that commit is still the PR head. Check the last one immediately before merging — a push between the test and the merge invalidates the result. If any condition fails, say which and stop.
Ver no GitHub