STAGE 4 / Native automation · LESSON 24
What can this code touch?
Outbound HTTP requires network-client authority. Server listeners need network-server authority. The convenience --allow-net grants both and is broader than a client-only lesson needs.
Native contract
Use the current HTTP API documentation for accepted options, response shape, timeouts, body limits, and error behavior. Do not assume every helper has the same signature as another language's client. Network failures and non-success HTTP statuses are different conditions and need explicit handling.
For deterministic testing, isolate a pure response evaluator. The example processes a fixture response dictionary using an application-owned schema, not a claimed native HTTP return shape. The stage build separately exercises a real loopback HTTP request against a fixed local server.
Private destinations
--deny-private-net rejects private, loopback, link-local, multicast, and unspecified destinations for supported outbound calls. This protects against a class of unwanted internal destinations. It is not a universal network sandbox or authentication system.
A local fixture server intentionally uses loopback, so its integration test has a documented exception and never combines that address with a claim that private destinations were denied. A separate denial drill verifies the private-network policy.
Professional pattern
Validate an operator-controlled endpoint, set finite timeouts, bound response size, inspect status, and validate the decoded body. Keep provider data separate from instructions that choose local authority. A response saying “retry at this URL” is untrusted input, not permission to contact an arbitrary host.
Common mistakes
Do not make the default suite depend on a live public endpoint. Do not retry malformed requests forever. Do not confuse a successful TCP connection with a valid application response. The opt-in live exercise is a deployment check, while the local fixture remains the repeatable contract test.
Working example
func accepted(response) {
return response["status"] == 200 && response["body"]["ok"] == true
}
assert_equal(accepted({"status": 200, "body": {"ok": true}}), true)
assert_equal(accepted({"status": 503, "body": {"ok": false}}), false)
print("response policy verified")
Run it
From the course repository root, use the pinned Kujo 1.3.1 runtime.
kujo check examples/24.kujo
kujo run --untrusted examples/24.kujo
Captured output
response policy verified
Break it and diagnose it
This drill has no network-client allowance. The capability check must reject the call before network access. The project integration gate tests real local HTTP separately.
http_get("http://127.0.0.1:1/")
kujo run --untrusted examples/24-break.kujo
Exit status: 4. Captured diagnostic:
[KUJOVM001] [vm] Runtime Error: Capability denied: network-client required for http_get; rerun with --allow-net-client
--> 0:0
= help: Rerun with the required --allow-* flag, or remove the host-effect operation.
Exercise
Build a response evaluator with success, non-success status, and malformed-body cases. Run the local fixture integration project. Then opt in to a permitted external endpoint with a timeout and private-destination denial.
Checkpoint
- I distinguish transport, HTTP status, and schema validity.
- I keep default tests fixture-backed.
- I document intentional loopback exceptions.
Verified 2026-09-06 · Official Kujo 1.3.1 release · Source contract · Download example