Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ the conversation toward config before anyone writes code.
If a vendor is nearly compatible and something small blocks it, that is a bug in
the adapter worth fixing, not a reason for a fourth one.

**A new adapter config must not commit the vendor's published rates.** Name the
tariff page and leave the figures to the operator's own `--pricing` table. Some
vendors' terms make their pricing confidential and override the usual
public-knowledge exclusion, so copying a rate out of a public page into a file
this project publishes is a disclosure by this project. Secret scanning will not
catch it, because a price is not a credential format; see SECURITY.md and the
test named there.

## The rule about figures

**No figure may be rendered without its n and its null.**
Expand Down
34 changes: 34 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,40 @@ Please do not open a public issue for a security problem.
it does not change the answer.
- `.env` is gitignored. `.env.example` is the template and holds no values.

## What the automated controls cover, and what they do not

This repository has secret scanning and push protection enabled. Both work by
recognising **credential formats**: a token that looks like a token gets caught,
and push protection rejects the commit before it lands. That is the right
control for a leaked key and it is the reason a key has never reached a commit
here.

It is worth being precise about what that leaves.

The closest thing to a disclosure this project has actually had was not a
credential. It was a **vendor's price**, quoted from their documentation into a
shipped config file, under a customer agreement that makes pricing information
confidential and expressly overrides the usual public-knowledge exclusion. No
scanner recognises a price. `0.042` is a float. Push protection would have
passed it through without a murmur, and did, until it was caught by reading.

Contractual confidentiality is not a pattern-matching problem, so it does not
get a pattern-matching control. What guards it here is design and a test:

- **Design.** plumbline ships no pricing figures for a vendor whose terms treat
them as confidential. The shipped entry names the tariff page and prices
nothing, and the operator supplies the numbers themselves through
`--pricing`, in their own working copy. Reading a published page and writing
the number down is the operator's act, not this project's.
- **A test.** `tests/test_cost_and_latency.py::test_no_shipped_entry_states_a_figure_for_the_confidential_vendor`
asserts that no shipped entry for that vendor carries a numeric price, in
either a price field or its source string. It fails if a number is put back
in a price field, and it fails if a price is quoted in the prose around one.
Both paths were verified by injecting a figure and watching it go red.

If you are reviewing a change that touches pricing, that test is the control.
Do not assume a green secret-scanning badge says anything about it.

## Run artifacts contain your data

This is the part worth pausing on.
Expand Down
15 changes: 15 additions & 0 deletions docs/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ Settled during the build. Reopen one only with a reason, not from scratch.
about the system under test. A decline is recorded as a refusal with its
category and counted. The tradeoff is stated at the call site in
`adapters/generative.py`; it is not an oversight.
- CodeQL default setup is kept for its **`actions`** coverage, not its Python
coverage. Workflow script injection is a real class of bug and `ci.yml` is
where it would hide. The Python queries are expected to be low yield on this
codebase: it is a CLI with no attacker in its threat model, run by an
operator on their own data with their own key. The first full scan produced
exactly one alert, a false positive on a test assertion
(`py/incomplete-url-substring-sanitization`, a substring check that makes no
security decision), dismissed with that reasoning. **Turn it off if a second
false positive appears on ordinary work**; at that point it is costing review
attention it is not repaying. It is a setting, not a workflow file, so
disabling it is one API call and leaves no trace in the tree.
- Secret scanning and push protection guard credential formats and nothing
else. The disclosure risk this project actually has is contractual, and the
control for it is the `--pricing` design plus a test. SECURITY.md says so in
full, because a green scanning badge invites the wrong assumption.

## Live validation

Expand Down
Loading