bastion 0.58.0
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m5s
ci / fuzz (push) Successful in 4m10s

This commit is contained in:
Privatae
2026-10-29 15:54:51 +00:00
parent 081763a675
commit 01889e2a48
37 changed files with 5629 additions and 90 deletions
+27
View File
@@ -62,6 +62,14 @@ says so. Those parts are enforced only by the code as written.
| | `localdeny_test.go`: `TestTheLocalSwitchCanOnlyEverRemoveReach` | Switching a capability off on this machine never turns a refusal into an allow. |
| Fixed argv | `observe_ops_test.go`: `TestObserveArgsNeverReachArgv` | Shell metacharacters and flags sent as arguments to every observe op are refused or never reach a command line, and each op runs only its pinned argv. Linux only. |
| | `contextextract_test.go`: `TestCtxExtractRefusesAnUnknownTool` | Text extraction runs only tool names from its fixed table. |
| | `observe_reads_linux_test.go`: `TestObserveJournalRunsOnlyItsPinnedArgv` | `observe:journal` runs `systemctl list-units`, `systemctl list-unit-files` and one pinned `journalctl`; the unit reaches `journalctl` only as `--unit=` with a name one of those lists holds, and a unit this machine does not have, or knows only as not found, is refused before `journalctl` runs. Linux only. |
| | `observe_reads_linux_test.go`: `TestObserveLoginsRunsItsPinnedArgv` | `observe:logins` runs one pinned `journalctl` whose only caller value is a whole number of hours; without access to the system journal it runs nothing and its counts read -1, never 0. Linux only. |
| | `observe_reads_linux_test.go`: `TestObserveLoginsCountsOnlyRootsSSHDLines` | Every match `observe:logins` gives `journalctl` also needs `_UID=0`, so a line another account wrote under a process named sshd, or from a shell left in ssh.service, is never counted. Linux only. |
| | `observe_reads_linux_test.go`: `TestObserveFoldersReadsOnlyTheFolderItStatd` | A folder swapped for a link between the walk's stat and its open, or reached through a folder above it that was, is not read and is listed as changed. Linux only. |
| | `observe_reads_linux_test.go`: `TestObserveFoldersStartsNoWalkPastTheStuckOnes` | Past four walks still inside a read that has not returned, `observe:folders` answers at once and starts no walk; a walk that comes back frees its place. Linux only. |
| | `observe_reads_test.go`: `TestObserveReadsRefuseBadValuesWithTheRule` | A relative folder path, one with `..` or under `/proc`, a unit name outside systemd's alphabet, shaped like a flag or naming a template, and a depth, window or port out of range are refused at exit 2 with the rule broken, without repeating the value. |
| | `fuzz_observe_test.go`: `FuzzFolderPathIsAbsoluteCleanAndOffTheKernelTrees` | Whatever the input, a folder path that passes is absolute and clean, holds no `..` and no control character, and is outside `/proc`, `/sys` and `/dev`. |
| | `fuzz_observe_test.go`: `FuzzUnitNameIsSystemdsAlphabet` | Whatever the input, a unit name that passes is in systemd's unit-name alphabet, at most 255 characters, ends in a unit type, does not start with `-`, `.` or `@`, and is the input itself or the input with `.service`. |
| | `claims_unix_test.go`: `TestTheAllowlistedOpIgnoresTheCallersArguments` | `uptime`, sent through the management lane with hostile arguments, runs its program with none. |
| | `claims_static_test.go`: `TestTheAllowlistedOpRunsItsTableArgvOnly` | The allowlisted table is exactly `uptime` with no arguments, and the one command the lane starts is built from the table's argv alone. |
| | `claims_static_test.go`: `TestFileHandlersStartNoShell` | Nothing a context, store or backup handler can reach runs a shell; the one process any of them can start is the local search agent's Python, which `dcn_grant_sync` brings up. |
@@ -101,6 +109,24 @@ says so. Those parts are enforced only by the code as written.
| | `ops_action_linux_test.go`: `TestActionApplyOfAnotherChangeListRunsNothing` | An apply whose change list differs from the approved one is refused before the program starts. Skipped where action ops cannot run. |
| | `ops_action_test.go`: `TestActionManifestRefusesWhatIsNotDeclaredOrNotBounded` | An unknown verb or argument, a workload, container, unit or tree named by a parameter, an undeclared credential, verbs without root, a destination on loopback, link-local or a metadata service (also inside NAT64 or IPv4-mapped IPv6), the bastion's own unit, a tree on a credential store, a tree or container moved twice by one op, and more, are each refused when the op arrives. |
| | `ops_action_test.go`: `TestSealedCredentialsOpenOnlyForThisRunAndThisOp` | A credential sealed for another run, to another machine, tampered, expired, undeclared, missing or sent twice is refused. |
| A standing grant holds to its bounds on the machine | `ops_skill_bounds_test.go`: `TestGrantOutsideItsWindowIsNotNowAndSpendsNothing` | An apply outside the grant's window (days, hours, zone, read on the machine's clock) does not run, spends no use and is no strike, and says when the window opens; a dry run is not held; arguments outside the op are still refused. Inside the window it runs and spends one use. |
| | `ops_skill_bounds_test.go`: `TestGrantInsideItsMinIntervalDoesNotRun` | An apply inside the approved interval since the last one does not run, spends nothing and is no strike; past it, it runs. |
| | `ops_skill_bounds_test.go`: `TestGrantPerDayHoldsAcrossARestart` | The runs are logged in the grant's record on disk, and another process reading that record holds the third run in 24 hours as the first did. |
| | `ops_skill_bounds_test.go`: `TestGrantWithATamperedRunLogIsNoGrant` | A record whose run log, uses, approver or seal was edited outside the bastion, or that carries no seal, holds no grant. |
| | `ops_skill_bounds_test.go`: `TestGrantDiesWithTheKeyThatApprovedIt` | A grant keeps the key that approved it; with that device key unpinned, or the console factor enrolled again, it is refused, and unpinning drops it so pinning the key again does not bring it back. |
| | `ops_skill_bounds_test.go`: `TestGrantDropGoesThroughAQuarantine` | `op_grant_drop`, of one grant or all, goes through while the host's writes are quarantined, with no approval. |
| | `fuzz_grants_test.go`: `FuzzAGrantsRunBoundsHoldWhateverTheHostSends` | A window or rate the machine accepts is one it can hold, and no run inside an interval or past a day's count is let through. |
| An op with no program needs no sandbox, and a program still does | `ops_skill_bounds_test.go`: `TestProgramOpStillRefusedWithoutTheSandbox` | On a machine with no overlay, a files op and an action op with a program are refused before anything runs. |
| | `ops_skill_bounds_test.go`: `TestVerbsOnlyOpShippingRunIsRefused` | An op with `interpreter: none` that ships a `run` file is refused at sync; without one it is held. |
| | `ops_verbs_only_linux_test.go`: `TestVerbsOnlyOpRunsWithNoOverlay` | On a machine with no overlay, an op with no program dry-runs as its verbs' own read, applies its verbs once under an approval bound to that list, and is refused, as the machine's own state and no strike, where a verb's tool is missing. |
| On your own machine, an action op reaches the internet, never your network | `ops_action_local_test.go`: `TestALocalBoxRefusesAnActionOpThatDeclaresAPrivateNetwork` | Through `op_sync` on a local, unanchored machine: an op declaring `10.0.0.2:80`, a `192.168.0.0/16`, `172.16.0.0/12`, CGNAT, ULA or benchmarking address, or `10.0.0.2` inside NAT64 or 6to4, is refused with the reason and what to do instead, and nothing is held; a public address and a name are held. |
| | `ops_action_local_linux_test.go`: `TestALocalBoxRefusesANameThatResolvesToAPrivateNetworkAtApply` | On a local machine a name that resolves to a private address, alone or beside a public one, is refused when an apply resolves its destinations; a public name resolves to its address; on an anchored machine the private name resolves. |
| | `ops_action_local_linux_test.go`: `TestAPrivateDestinationHeldWhileAnchoredIsRefusedAtApplyOnceTheAnchorIsGone` | An op whose destination is `10.0.0.2:80` or its IPv4-mapped form resolves at apply on an anchored machine; once the machine is local, the same destinations are refused at apply. |
| | `ops_action_local_linux_test.go`: `TestALocalBoxNeverFetchesAVerbsRepositoryFromAPrivateNetwork` | On a local machine a verb's fetch (the ancestry check `k8s.set_image` makes) of a repository whose host resolves to a private address, to a public and an IPv4-mapped private one, or to a link-local one is refused with the reason before git runs; a public host is fetched with git pinned to the checked address (IPv6 bracketed, the URL's port kept), a git that would drop the pin is refused, and an anchored machine fetches from its private forge unpinned. |
| | `ops_action_local_linux_test.go`: `TestAnAnchoredBoxNeverFetchesAVerbsRepositoryFromItselfOrTheMetadataService` | On an anchored machine a verb's fetch (the ancestry check `k8s.set_image` makes) of a repository whose host resolves to loopback, to a public address beside an IPv4-mapped loopback one, to a link-local address, to a metadata service or to this machine's own address is refused with the reason before git runs; a private forge is fetched pinned to its address. |
| | `ops_action_local_linux_test.go`: `TestALocalBoxNeverPutsLiveAnImageFromARegistryOnItsNetwork` | On a local machine `k8s.set_image`'s plan and apply refuse an image whose registry is a name resolving to a private address, a private address, `localhost` or a link-local address, with the reason, and set nothing; a public registry and a Docker Hub repository pass the registry check; an anchored machine keeps its private registry. |
| | `ops_verbs_only_linux_test.go`: `TestSetImageNeedsGitForItsAncestryCheck` | `k8s.set_image` names kubectl and git as the tools it runs, and `tree.checkout` git; as root, a machine with kubectl and no git is told by the verb check and the beat that it cannot run `k8s.set_image`. |
| | `ops_action_local_test.go`: `TestAnAnchoredFleetKeepsItsPrivateDestinations` | Through `op_sync` on an anchored machine: ops declaring a private, CGNAT or ULA address are held; loopback is still refused. |
| Root verbs move only forward | `ops_verbs_linux_test.go`: `TestSetImageTouchesOnlyTheNamedContainerAndOnlyForward` | Against a stand-in kubectl: a digest with no receipt, a receipt from another repository, a container the workload lacks, a live image this machine never rolled (a receipt for it included), another image and a backward commit are each refused with nothing set; a forward roll sets exactly the named container and records it; an image already set still waits for its rollout, and fails when it does not finish. The ancestry answer is a stand-in here. |
| | `ops_verbs_linux_test.go`: `TestAncestryByFetchRefusesABackwardOrSidewaysCommit` | With real git, the ancestry check `k8s.set_image` makes accepts a forward commit or the same one, and refuses a backward, sideways or unknown commit. |
| | `ops_verbs_linux_test.go`: `TestTreeCheckoutMovesOnlyForward` | With real git: a tree moves forward to the exact commit, runs none of its own hooks, leaves untracked files and nested repositories alone, and refuses a backward or sideways commit, another origin, local changes and a config that could run a program. |
@@ -237,6 +263,7 @@ says so. Those parts are enforced only by the code as written.
| Observation changes nothing on the machine | `observe_endpoints_test.go`: `TestObserveEndpointAllowedIsTheInverseOfObserveNet` | The monitoring ops may reach only private addresses, exactly the ones `observe:net` refuses. |
| | `observe_endpoints_test.go`: `TestObserveDialControlRefusesPublicAtConnectTime` | A public address is refused at the socket, so a DNS answer cannot move a query outside. |
| | `observe_endpoints_test.go`: `TestObserveNeverFollowsARedirect` | A redirect from a monitoring endpoint is reported as a failure, and its target is never fetched. |
| | `observe_reads_linux_test.go`: `TestObserveCertReadsOnlyThisMachinesListener` | `observe:cert` is refused for a port no listener on this machine holds, and never dials an address a listener is bound to that this machine does not hold. Linux only. |
| | `claims_static_test.go`: `TestObserveOpsWriteNothing` | Nothing an observe or computer op can reach writes, removes, renames, changes permissions on, mounts or signals anything, apart from the bastion's own audit line and its journal of observe results; the programs those ops run are a fixed list of reads. |
| | `claims_static_test.go`: `TestNoInputInjection` | No input-injection program is run, no Windows input API is loaded, and no script the computer ops run asks for a keystroke, a click or an accessibility action. |
| A backup's key goes to a host only when you approve it here | `backupreseal_test.go`: `TestBackupResealWaitsForThePersonThenDeliversToTheHostOnly` | Through the management lane: a request is filed pending and hands out nothing; another pairing cannot read it; after approval here the host receives the record sealed to its key only; a refusal hands over nothing; a decided request cannot be decided again. |