Skip to content

disclosure: a mistyped run id or repository is reported as "Only the SHAPE of the run is public", exit 0, and the verdict text ignores exposedNames #303

Closed

Description

@StepenkoAnatoli

What's wrong

disclosure answers the question "what can a stranger see of this run?" with exit 0 and "Only the SHAPE of the run is public" when the run it was asked about does not exist, because the arguments named nothing. Measured on main at 9a47439, anonymous, against this repository:

$ node research-kit/bin/disclosure.mjs --repository StepenkoAnatoli/Research-Kit --run abc
anonymous probe of StepenkoAnatoli/Research-Kit run NaN

  404  run metadata           refused 404
  404  jobs and step names    refused 404
  404  run timing             refused 404
  404  artifact listing       refused 404
  403  repository secrets     refused 403
  -    artifact DOWNLOAD      not tried  (nothing to try)
  -    job LOGS               not tried  (nothing to try)

names and metadata exposed : false
content exposed            : false
the subject itself         : not checked - pass --topic to search for it

Only the SHAPE of the run is public: names, sizes, timings, step titles.
...
exit=0

--repository Research-Kit --run 12345 (no owner) gives the same verdict with 403 on every line, exit 0. With --json the first case carries "runId": null.

Three things combine:

  1. bin/disclosure.mjs line 65 passes Number(flags.run) without checking it: abc becomes NaN, and the probes ask GitHub for /actions/runs/NaN. --repository is passed as any string (line 64); there is no OWNER/REPO check. Every other CLI that takes a number goes through checkFlagValues (artifact.mjs refuses a bare or non-integer --run-id by name since fix(artifact): a bare value flag is refused by name, not written as "true" or 1 #283).
  2. summarise in lib/disclosure.mjs (line 120) counts a refusal as an answer, which is right for a real run, so every-probe-refused is "conclusive" and exitCode returns 0. The same function's comment records the neighbouring case as a found defect ("with no network, every probe was unreachable and the verdict still read as clean, exit 0", 2026-09-27). Every probe refused because the question named nothing is that defect one step over.
  3. render prints "Only the SHAPE of the run is public: names, sizes, timings, step titles" from the else branch (line 180) whenever nothing leaked and the report is conclusive, without reading exposedNames. Here exposedNames is false on the line above it: the run metadata was refused, so the shape was not public, and the closing text contradicts the report's own numbers.

The command is the one the ADR-0031 argument rests on ("that is why the collector keeps the topic out of the run name"). A typo in the run id turns it into a clean bill for a run nobody looked at.

A real private repository also answers 404 to a stranger, so a 404 on the run alone cannot tell "private" from "mistyped". The arguments can be checked before any request, and the verdict text can stop claiming a shape it did not see.

The fix

  • --run through checkFlagValues as { int: true, min: 1 } and --repository as a value matching ^[^/\s]+/[^/\s]+$, exit 3 ("could not measure") by flag name, before honourEnvProxy() and before any request. Same { exit: 3 } shape artifact.mjs uses.
  • In render, when exposedNames is false and the report is conclusive, say what was measured: "Nothing of this run was readable anonymously - not even its shape. Either the repository is private to a stranger, or no run with this id exists there; GitHub answers 404 to both, and this probe cannot tell them apart." and not "Only the SHAPE of the run is public".
  • Optionally, in probeRun, one more unauthenticated GET on /repos/OWNER/REPO when the run metadata answers 404: 200 means the repository is public and the run does not exist (then the report is not conclusive, exit 3); 404 means the repository itself is not visible to a stranger, which is the private case. That adds a probe to PROBES, so it is a freeze question (ADR-0117) and can wait; the two parts above are a bug fix.

Test

In disclosure.test.mjs, with the fake fetch the file already uses: every probe answering 404 renders no line claiming the shape is public, and names the two causes. In cli.test.mjs (or the CLI test in disclosure.test.mjs): --run abc, --run 0 and --repository Research-Kit exit 3 naming the flag, and the fake fetch is never called.

Checking your change

node research-kit/bin/selftest.mjs disclosure cli

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions