repolane v0.11.0 · open source

Guides

Contributing and reporting

How to run the tests, send a change, ask a question, and report a bug or a way past the guard.

On this page

This page is the short version of the repository’s CONTRIBUTING.md. Where they differ, the repository is the authority on process.

Where to go

You haveGo to
a bug or a feature requestIssues. The templates mostly ask for the command you ran and what it did
a question, or “is this a bug or am I holding it wrong”Discussions
a way to get the guard to allow something it should refuseprivate reporting, below. Not a public issue
something broken and you want to fix it yourselfWhen something goes wrong, then the rest of this page

You do not need a fix in hand, or to be sure it is a real bug, to file one.

What the repository is

A folder of bash scripts and standard-library Python: the two big Python programs are scripts/hooks/guard.py and scripts/board/server.py, and a few small helpers sit in scripts/. The Python package (pyproject.toml, src/repolane/) is a thin launcher that bundles those same files; it has no dependencies, and that is deliberate: Repolane should not need anything beyond git, bash and python3 at run time. A change that adds a dependency needs an argument for itself before it needs code.

Run the tests

bash scripts/hooks/test-guard.sh        # the guard's cases
lane doctor -v                          # the named probes, the wiring check, and the same suite
bash tests/run-all.sh                   # the lane scripts: dispatcher, memory, upgrade, park/done/brief, secret names
bash scripts/board/smoke.sh             # starts the board on a spare port, checks its endpoints, then runs test_board.py

tests/run-all.sh runs the tests/t_*.sh suites, each in its own sandbox; smoke.sh ends with the board’s unittest cases. A CI workflow (.github/workflows/tests.yml) runs all three on every push and pull request, on ubuntu-latest and on macos-latest pinned to /bin/bash 3.2. A second workflow (test.yml) runs only the guard suite on Ubuntu for pushes and pull requests to main and release.

The guard suite builds its own throwaway setup under a temp directory and runs every case against a copy of guard.py there, with HOME pointed at a fake home inside that directory. It never reads or writes your real lanes, base clones or memory, and it does not depend on where your $HOME is. On success it prints N/N cases passed and ALL PASS, and it exits non-zero on any mismatch. There is no hard-coded count to keep in step: every section must run at least one case, every case must also see the guard exit with status 0, and the totals must add up. If the fixture cannot be built the run fails; it never skips.

If you touch guard.py, add a case for what you changed, in both directions: the thing that should be refused, and the near miss that should still be allowed. A rule with no test is a rule that will quietly stop working. Most regressions the suite has caught were rules that became too broad.

Send a change

  1. Open an issue first if it is a design change or a new rule. For a bug or an obvious fix, go straight to a pull request.
  2. Branch from release, not main. main only moves by a “Release vX.Y.Z” pull request merging in from release. Your pull request into release is the whole contribution; you never touch main or version numbers. See docs/releasing.md.
  3. Match the surrounding style: set -u, explicit error paths, comments that say why.
  4. Run bash scripts/hooks/test-guard.sh (and bash tests/run-all.sh if you touched a lane script) in your checkout of the repo, and lane doctor in a workspace if you have one.
  5. Open the pull request against release. Say what changed and whether the suite passes. If the change is user-visible, add an entry under ## [Unreleased] in CHANGELOG.md; the bump type is read from which headings you use (### Added, ### Fixed, ### Removed).

Keep a pull request to one thing: a guard rule and a board tweak are two.

Docs are part of the change. If the code says one thing and a page says another, the page is a bug. A change that alters behaviour and leaves the docs describing the old behaviour is not finished.

If what you want is a refusal specific to your project, you probably do not need to change guard.py: see Extending.

Reporting a security problem

If you find a way to get the guard to allow something it should refuse (a path that escapes the lane, a chained command that slips past a rule, a way to read a secret file), report it privately: Report a vulnerability in the repository’s Security tab. GitHub asks you to sign in. Please do not open a public issue for a bypass: every existing install stays exposed until a fix ships.

Include the kind of command or path shape that gets through and how you ran it. Once a fix is released the advisory is published with credit to you unless you would rather stay anonymous.

In scope: the guard’s behaviour, meaning anything the Rules page says should be refused and is not; and the board listening beyond 127.0.0.1, making an outbound request other than the documented ones (gh pr view polling, the Push and Pull you click), or leaking a secret’s contents rather than its key names.

Not in scope: anything that needs an attacker who already has write access to your repos or your machine.

What is already known. The security model documents the design limits: the tools the matcher does not cover, the parts of a command the guard cannot see (a script run by name, a variable set elsewhere, interpreter code that computes a file name, the Agent call itself, WebFetch, MCP), the paths outside $HOME that are not judged, the ALLOW_DEFAULT_BRANCH_PUSH=1 marker being advisory, and a board token that any local account able to reach the port can read. These are the limits of a guardrail. A new way past a check the docs say works is what the private channel is for.

Repolane is maintained on a best-effort basis and provided as is, under the Apache License 2.0. Participation is under the repository’s Code of Conduct.

Next steps

  • Security modelWhat the guard checks and where it stops, before you report a bypass.
  • ExtendingYour own rules, commands, shared rules and secret files.
  • CommandsEvery lane command, with what it does.
  • TroubleshootingHow Repolane breaks and what to type.