Skip to content

feat: the failure-injection levers get an HTTP surface - #66

Merged
lex00 merged 2 commits into
mainfrom
inject-http-surface
Aug 3, 2026
Merged

feat: the failure-injection levers get an HTTP surface#66
lex00 merged 2 commits into
mainfrom
inject-http-surface

Conversation

@lex00

@lex00 lex00 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Closes #56. Ticks one of #54's four honest items.

m80 could force a build to FAILED and a connector to any of its seven reason codes, and only from Go. A test importing m80 could drive them; a suite pointed at the container could not reach them at all — backwards, since a container is what a consumer tests against.

docker run --rm -p 4290:4290 ghcr.io/intentius/m80 -enable-injection

curl -X POST localhost:4290/_m80/inject -d '{"target":"build","name":"doomed"}'
curl -X POST localhost:4290/_m80/inject \\
     -d '{"target":"connector","name":"egress","reasonCode":"SubnetOutOfIPAddresses"}'

Three deliberate choices

Keyed by name, not the ARN the issue sketched. A lever arms before the resource exists — that is what "the next build of this image fails" means — so at the moment of arming there is no ARN to name it with.

The response carries "injected": true. A state m80 reached under its own rules never carries it, so a consumer asserting on that field cannot mistake an injected FAILED for a real one. That was the issue's first requirement, and it is why the endpoint returns a body rather than a bare 200.

Off unless -enable-injection. Nothing under /_m80/ is signed, so anything reaching the port can arm a lever; the flag is the consent, same posture as -serve-sts. Without it the route is still registered and answers 404 naming the flag — the requirement was that the levers not be reachable by accident, not that they be undiscoverable, and a bare 404 is indistinguishable from a typo in the path.

Verified against the container

Not just in-process. Built the image, armed a build over HTTP, created it with the AWS CLI, watched the version settle FAILED:

{"injected":true,"target":"build","name":"doomed","armed":"the next build of image \\"doomed\\" settles FAILED"}
…
"imageVersion": "1.0", "state": "FAILED"

11 new tests, full suite and -race clean, scripts/smoke.sh still walks the README end to end.

docs/lifecycle.md claimed this surface was needed for #18. It was not — that was corrected in the issue and the page now says what it is actually for. scope.md, api-surface.md and the README all name the flag.

lex00 added 2 commits August 2, 2026 19:32
m80 could force a build to FAILED and a connector to any of its seven
reason codes, and only from Go. A test that imported m80 could drive them;
a suite pointed at ghcr.io/intentius/m80 could not reach them at all —
exactly backwards, since a container is what a consumer tests against. A
KubeMicroVM test wanting to watch its operator handle a failed image build
had no way to cause one.

POST /_m80/inject arms either lever. Three things about the shape are
deliberate.

Keyed by name, not the ARN the issue sketched. A lever arms before the
resource exists — that is what "the next build of this image fails" means
— so at the moment of arming there is no ARN to name it with.

The response carries "injected": true. A state m80 reached under its own
rules never carries it, so a consumer asserting on that field cannot
mistake an injected FAILED for a real one. That was the issue's first
requirement and it is the reason the endpoint returns a body at all rather
than a bare 200.

Off unless -enable-injection. Nothing under /_m80/ is signed, so anything
that can reach the port can arm a lever; the flag is the consent, same
posture -serve-sts takes. Without it the route is still registered and
answers 404 naming the flag — a bare 404 is indistinguishable from a typo
in the path, and the issue's second requirement was that the levers not be
reachable by accident, not that they be undiscoverable.

api.Server grows a Handle method for this. Operations still go through
Register, which panics on an unknown one, so nothing outside the Routes
table can claim an operation's path.

Verified against the container rather than in-process: armed a build over
HTTP, created the image with the AWS CLI, and watched the version settle
FAILED. docs/lifecycle.md said this surface was needed for #18 and it was
not; it now says what it is actually for.
The docs site mentioned -serve-sts in four places and the README in none.
It is the flag that decides whether the KubeMicroVM operator starts at
all, and the README is the page that leads with running the operator, so
of everything that could have drifted this was the worst candidate.

Found by diffing the runtime flags each surface names rather than by
reading, which is the only way this stays true — #54 lists README-versus-
docs drift as an open item precisely because they have drifted before.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failure-injection levers have no HTTP surface, so a container consumer cannot reach them

1 participant