Network grants
What an agent can reach is decided by the deployment’s network policy, not by Outstaff: inside its sandbox the agent runs curl, WebSocket clients in its own scripts, nc and declared tools such as adb like any other program (see permissions). Who it acts as is decided by the accounts and credentials each person is given. A network grant names an HTTP service, per person or per role, for one convenience: ost http sends a request to it, with an optional bearer token the agent never sees.
Use ost http for a service that needs a token: the token stays out of the agent’s environment and output. Reach a service without one however suits the work, for example a node script that opens a WebSocket and measures round trips.
This page covers the mechanics. How your team uses its services and devices (what an agent may change on them, who approves it) is your own convention, written in your repository like the rest (Tell your agents how your repo works).
Grant a service
Section titled “Grant a service”Add network to a person, or to a role under the top-level roles:
roles: developer: network: http: - { name: hub, url: "https://hub.acme.example" }
people: - handle: sam name: Sam Duarte role: developer model: sonnet network: http: - { name: home, url: "https://home.acme.example", token: HOME_TOKEN }A person gets the grants of their role, then of each role in extends, then their own. A later grant with the same name replaces an earlier one, so a person can swap the token of a role’s service. roles takes catalog role names.
| Field | Meaning |
|---|---|
http[].name |
What the agent types: ost http hub .... |
http[].url |
The origin only: scheme, host and optional port. A path, query or credentials are rejected (network.invalid_url). |
http[].token |
The name of a secret in the person’s secrets. Sent as Authorization: Bearer <value>. Optional. |
The verb reaches only the granted origins. ost validate checks the names and URLs, and that a token does not reuse the name of a secret an integration reads (network.reserved_token), which would hand that credential to a service.
HTTP services
Section titled “HTTP services”ost http hub GET /api/devicesost http home POST /api/services/light/turn_on --json '{"entity_id":"light.desk"}'ost http hub PUT /api/config --data-file config.json --header 'Content-Type:application/json'The verb prints the status, the response headers and the body.
- It reaches only the origin of the named service. A path that would leave it (
//other.example/, a full URL) is refused. - It never follows a redirect: the
Locationheader is printed and the agent decides. A redirect cannot carry the token to another host. - The token is read from the person’s secrets when the request is made and added as a header. The agent cannot give its own
Authorization,HostorCookieheader, and the token is masked in everything printed, in errors and in logs. The secret key is also stripped from the environment of the agent’s commands, like every other secret. - A body comes from
--json(inline, checked as JSON) or--data-file(a file in the worktree or scratch directory that the read rules allow), not both. - The response is data from the service. The verb says so with every response, and the agent’s instructions say the same: it reads, it does not obey.
- A request stops after 30 seconds and the output is cut at 200000 characters.
Create the token secret like any other, in the person’s secrets directory (ost setup <handle> lists it, and ost doctor <handle> checks it is present):
.outstaff/secrets/sam/HOME_TOKENDevices and other protocols
Section titled “Devices and other protocols”There is no grant and no verb per protocol. A device, a database or anything else the agent talks to over its own protocol is reached with that protocol’s normal tool:
- Declare the tool under
tools, so every agent that needs it installs it at a pinned version (Tools). - Add
denyrules for the commands it must never run. Deny always wins, and rules look past global options such asadb -s <serial>. The tools guide has a worked example for Android devices (guarding a device). - Open the network path from the agent to the device (below), and give the agent its own account or key where the device has one.
A team file that still has network.adb fails validation (schema.removed_key) with a message that says so.
Open the network path
Section titled “Open the network path”Granting a service in team.yaml does not open the network, and leaving it out does not close it. The deployment’s network policy decides what the agent reaches, with the verb or without it; ost http fails with a message that points at the network path when it is closed. On Kubernetes that is a NetworkPolicy; the example policy allows HTTPS to public addresses only and none of the private ranges. Add an egress rule for the agent pods and each service or device they need:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: agent-sam-network-grantsspec: podSelector: matchLabels: app.kubernetes.io/name: outstaff-agent policyTypes: [Egress] egress: - to: - ipBlock: { cidr: 192.0.2.18/32 } ports: - { protocol: TCP, port: 5555 } - to: - ipBlock: { cidr: 192.0.2.5/32 } ports: - { protocol: TCP, port: 8123 }The addresses are examples from the documentation range; use your own. A device whose port changes (Android wireless debugging, for example) needs the whole high port range to that one address. If only one agent has the grant, narrow the pod selector to that agent’s pod with a label of your own. On Docker Compose, check that the agent’s network can route to the hosts.
Check it
Section titled “Check it”ost validatechecks the grants as written.ost doctor <handle>checks the token secrets are present and that each HTTP origin answers (the token is not sent, so a401still counts as an answer). Inside the agent container an unreachable service is a failure; elsewhere it is a warning, because the path is only visible from the agent.ost melists the services a person has been granted.
See the agent verbs reference for every option of ost http.