Skip to content

Manage a test environment

A verify run needs a target that is up and identities that are logged in. Bravos keeps both in an environment recipe, authored once per target and replayed deterministically after that. This page manages one.

The reason it is a recipe rather than a set of flags: an environment that differs between rounds makes verdicts incomparable. Round 3 finding nothing is only meaningful if round 3 attacked the same application round 2 did.

  • A target you are authorised to test, and Docker if Bravos is to start it.
usage: bravos env [-h] [--json]
{init,up,down,reset,health,show,login,auth,rm,list} ...
positional arguments:
{init,up,down,reset,health,show,login,auth,rm,list}
init have an agent author a recipe for a repository
up start the environment and seed it
down tear the environment down
reset tear down and rebuild from scratch
health check whether the target is up and has live sessions
show print the recipe
login capture or refresh auth profiles
auth show login readiness + the exact capture command per
identity
rm delete a saved environment recipe so the repo is re-
planned from scratch
list list known environments
Terminal window
bravos env list
nodegoat https://web.nodegoat.orb.local down 3/3 sessions
portainer-2-39-2 http://localhost:9010 down 0/3 sessions

Two numbers per environment: whether the target is up, and how many of its identities hold a session. down 3/3 sessions is the common state between runs: the application is not running, but the captured sessions are still on disk.

Terminal window
bravos env show nodegoat
nodegoat · https://web.nodegoat.orb.local
/Users/you/.bravos/envs/nodegoat
up (none)
health / -> [200]
login POST /login {userName, password}
identities (3)
np-admin admin admin
np-attacker user user1
np-victim user user2
review before use
- no up_command or compose_file: the environment cannot be started

The login line is the part that matters most and the part that is most often assumed. This target authenticates with POST /login and the fields userName and password, not /api/auth/login with {email, password}. Bravos captures sessions with its own headless login driven by that recipe, which is why a target with a non-standard login shape works at all.

review before use is the recipe telling you what it could not determine. Here there is no start command, so bravos env up has nothing to run and the target has to be started by hand.

Terminal window
bravos env health nodegoat
DOWN — https://web.nodegoat.orb.local/ unreachable: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1010)>
fail http: https://web.nodegoat.orb.local/ unreachable: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1010)>
ok session:np-admin: session present
ok session:np-attacker: session present
ok session:np-victim: session present

Run this before a run, not after. A target that is unreachable produces a run full of error_no_identities and zero requests were issued: every threat untested, no verdicts moved, and a report that is honest about it but has cost you the round. The failure above is a self-signed certificate, which is a different problem from a stopped container and needs a different fix.

session present means the file exists. It does not mean the session is still valid at the target.

Terminal window
bravos env auth nodegoat
nodegoat → https://web.nodegoat.orb.local
captured np-admin admin
captured np-attacker user
captured np-victim user
log these in (each in its own window):
cxg pentest auth --target https://web.nodegoat.orb.local --profile np-admin --auth-numbers 1 --label admin --tier 100
cxg pentest auth --target https://web.nodegoat.orb.local --profile np-attacker --auth-numbers 1 --label user --tier 20
cxg pentest auth --target https://web.nodegoat.orb.local --profile np-victim --auth-numbers 1 --label user --tier 20
then: bravos env auth nodegoat --check

It prints the exact cxg pentest auth command per identity rather than describing what to do. --check probes the target with each session instead of checking that a file exists, which is the difference between “captured” and “still works”.

bravos env login <slug> captures or refreshes them without leaving Bravos. During a run, bravos auto re-authenticates expired sessions itself and pauses only when a login genuinely needs a human; --no-capture makes it pause instead of driving interactive logins inline.

Terminal window
bravos env rm nodegoat # forget the recipe; the repo is re-planned
bravos env rm nodegoat --auth # also clear its captured sessions
bravos env reset nodegoat # tear down and rebuild from scratch

Remove the recipe when the target has changed shape: a new login flow, a new port, a different seeding path. A recipe that no longer matches the target is worse than none: it fails in the middle of a run rather than at the start.