DreadGOAD console and cloud operations - #463
Conversation
Add webapp/ (FastAPI backend skeleton + Vite/React frontend skeleton + ./dreadgoad-web launcher) and a --json output mode for 'dreadgoad lab status' that the ingestion hook will consume. Includes Go unit tests for the JSON marshaller. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add db.py: async SQLite layer (sessions/ranges/events/meta, WAL) with a single-worker executor serializing all writes for concurrency safety. Event log assigns monotonic per-session seq. Standalone-runnable tests cover CRUD, seq/replay/kind-filter, and a 100-write concurrency check (no lost/duplicate seqs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add labconfig (snapshot derivation: provider/region file-level, variant/lab/network per-env; 3-way topology seeding from config.json; versioned yaml backup + write-new-env), SessionService (create/list/get/delete + create-new-env), and session lifecycle + RangeView REST endpoints. Unit tests for snapshot/seeding/backup and session service; TestClient tests for the REST layer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the 14-command registry + provider-agnostic argv builder (injects --config/--env), a streaming CLI runner (cwd=repo root, SIGINT cancel), the per-session dreadgoad agent factory (Sonnet 5 via OpenRouter, fs-sandboxed, telemetry-free), and the multiplexed /ws/chat endpoint (direct-dispatch slash commands vs LLM free-text, event persistence + replay). Unit tests cover argv construction and the streaming runner; live chat is a manual test (needs OPENROUTER_API_KEY). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the post-command hook: map_range_status overlays live instance state (from lab status --json) onto config-seeded hosts — matched hosts get status/ip/cloud_id, unmatched config hosts go absent, unmatched instances ignored; infra nodes match via aliases (kali→attackbox). run_check wires it to CLI+DB with stale-preserving failure handling; fired after every command in the chat flow and surfaced as an inline check_run. 6 mapping unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
React SPA: two-pane shell + resizer, session tab bar + new-session modal, TerminalChat over a single multiplexed WebSocket (routes events per session_id, background tabs stay live), and RangeView (React Flow nodes by role + status/health badges, persisted layout). Adds the layout-persist REST endpoint. Builds clean under strict TS + vite; visual/interactive behavior is the manual test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Runner streams stdout lines live (async iterator) for a real-time tail; per-session cancel sends SIGINT (graceful unwind). Long-op status transitions (provisioning → running/destroyed/error), and a startup reconciliation that flips a crash-killed 'provisioning' session to 'interrupted'. WS-drop re-attach is via resume/replay. Tests cover live streaming and SIGINT-cancel-before-completion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lifecycle/verify commands work via the registry (Phase 3). Adds the /health overlay (range-level verdict from exit code; per-host --json is a follow-up) and topology re-seed after /extensions|/variant (merge_reseed preserves live state + layout while adding/removing nodes). /score builds score --report with the given path; remote SSM/SSH fetch of the report is a documented follow-up (needs cloud). merge_reseed unit-tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
run_check merged stderr into stdout, so a stray log/warning line on an otherwise-successful 'lab status --json' would corrupt json.loads and the range would never update. Add cli.capture() (separate streams) and use it in the hook; parse clean stdout, use stderr only for error messages. Adds a regression test and gitignores the tsbuildinfo artifact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply ruff formatting across the backend; resolve pyright errors (None-guards on Optional DB reads in tests, targeted type-ignore on the dreadnode Toolset async-CM protocol quirk in agent.py); guard a None session in chat direct-dispatch so a command for a deleted/unknown session returns an error instead of crashing the WebSocket. All tests still pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Findings from the phase-by-phase deep review, all with tests + green ruff/pyright/go: - P0: launcher pip works on uv venvs; lab status --json output documented (raw cloud fields). - P1: SQLite doc accuracy (WAL/NORMAL), get_events empty-kinds, connect() leak guard, meta test. - P2: REST create returns 400 on bad config/unknown env (was 500); derive_snapshot validates env. - P3: multiplexed WS runs turns in per-session tasks (cancel reachable, tabs don't freeze); per-session lock; agent eviction; chat.py tests. - P4: read-failure no longer clobbers session status; absent clears stale ip/cloud_id; run_check tests. - P5: RangeView live-refreshes on check_run; destructive tab-close confirm; stable message keys. - P6: cancel UI (Esc) + destructive-cancel warning; cancel->interrupted; process-group SIGINT; reconcile test. - P7: extension list --json + reseed surfaces extension nodes; /score fetches remote report (SSM/SSH); apply_health/reseed tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split slash commands into two dispatch paths: deterministic reads (+ /destroy) run the CLI directly, while the arg-flexible/mutating commands (/up, /provision, /reset, /variant, /extensions, /score) expand into a structured prompt and run through a constrained run_dreadgoad tool. Both paths share one run_cli pipeline, so agent-initiated ops get the same streaming, status, ingestion hook, and cancel behavior. The agent can no longer reach /destroy or raw cloud CLI (only run_dreadgoad + sandboxed fs). Prompt content moves to editable markdown under prompts/: system.md as the shared system prompt ($placeholder template) plus per-command guidance files whose flags were pulled from the CLI source (no hallucinated flags). Adding guidance to a command is now a drop-in file, no code change. Also hardens the command layer: resolve_bin prefers the repo's freshly-built binary over a possibly-stale PATH one (C3), direct commands reject stray args instead of shelling out to a CLI error (C4), and parse_command uses shlex so quoted paths survive (C5). Co-Authored-By: Claude <noreply@anthropic.com>
Add an ALFRED-style command palette to the chat input. A GET /api/commands endpoint serves the registry (name, description, dispatch, long_running, takes_args); the frontend fetches it once and renders a filtered dropdown as you type "/", with arrow/Tab/Enter navigation. Each row is tagged by dispatch (agent vs direct) so it's clear which commands take free-form args. Also retint the interactive accent from the inherited ALFRED gold (#f5c842) to a coral tint of the brand orange (#ff7a52), keeping the palette in one hue. Co-Authored-By: Claude <noreply@anthropic.com>
Two deferred command-review follow-ups: /score: the attack box is only known post-deploy, which left report fetching unusable. The ingestion hook now learns its cloud id from the same `lab status --json` read (the box appears there like any instance) and persists it to the session snapshot, so fetch has a target after any deploy/check. /health: add `health-check --json` emitting per-check results, and map them to per-host verdicts (any FAIL -> unhealthy) with a fallback to the old exit-code range verdict. A failing health check no longer marks the session errored — that outcome lives per-host, so the lifecycle stays running. Co-Authored-By: Claude <noreply@anthropic.com>
Render /health as a structured table instead of a raw JSON dump: the backend emits a health_report event (parsed from health-check --json, robust to requireInfra's stdout prefix) and suppresses the raw progress lines; the frontend shows per-check status with a pass/fail summary. Fetch the /score report via a new `dreadgoad score fetch` command that reuses the CLI's own connection machinery — SSM on AWS, Azure Bastion on Azure (auto-discovering the Kali VM + SSH key) — instead of hand-rolling scp in Python. This finally makes Azure report fetch work and stops the web app from reimplementing cloud connectivity. Guards against SSM's 24k-char stdout cap so a truncated report can't be silently mis-scored. Co-Authored-By: Claude <noreply@anthropic.com>
Document boot steps, env vars, the slash-command set (agent vs direct dispatch), the prompts/ layout, and the backend module map. Move the default port off 8420 to 7331 to reduce collisions with common local services; update the launcher and the vite dev proxy in lockstep. Co-Authored-By: Claude <noreply@anthropic.com>
Add an editable model field in the chat header so the operator can change
a session's agent model on the fly. The switch preserves the conversation:
under the session lock (so it can't race an in-flight turn), the agent is
rebuilt with the new model and the old thread's messages are grafted on, so
the dialogue continues on the new model. A status line records the change.
Backend: PUT /api/sessions/{id}/model + chat.swap_model; "status" added to
replayed event kinds. Frontend: ModelField, api.setModel, and a status
renderer. Per-session (not global), matching the multiplexed-session design.
Co-Authored-By: Claude <noreply@anthropic.com>
Let the operator set the LLM API key from the UI (⚙ in the tab bar) instead of only exporting it before launch, so the app can boot keyless and start agent turns without a restart. POST /api/settings writes the key into the named env var in-memory only — never persisted (honors no-creds-in-DB) and never returned. /api/config exposes api_key_set so the UI shows a "no key" warning until one is provided. Restrict api_key_env to key/token-shaped names so the endpoint can't overwrite PATH/LD_PRELOAD and hijack the CLI's terraform/aws/az subprocesses. Key stays per-process/global; model remains per-session. Co-Authored-By: Claude <noreply@anthropic.com>
New Session UX: - Empty state when no sessions exist (no chat/range panes until one opens). - Environment field is now a dropdown fetched from the chosen config (GET /api/environments), refreshed when the config path changes. - "New environment" tab creates an env in an existing config (mode="new") with collision + valid-config guards, then attaches. - Fix chat-input alignment (the `>` inherited a larger font than the box). Agent capability: - The agent's run_dreadgoad may now run ANY registered command (AGENT_RUNNABLE = all): reads (/instances, /health, …) to answer questions, and actions to perform them — so it stops probing with a mutating command when asked something read-only. Operator-typed reads still take the fast direct path (dispatch unchanged). - Reframe the system prompt: answer questions via the READ commands; confirm intent before state-changing ones (always before /destroy). Safety is by prompt (operator's choice), no hard block. - Harden list_environments against non-mapping YAML (400, not 500) and drop the now-unused AGENT_COMMANDS constant. Co-Authored-By: Claude <noreply@anthropic.com>
Health: `health-check --json` now streams NDJSON (one compact line per check as it completes, then the report line), so the web app shows each check live instead of a silent multi-minute wait; the report line drives the table + per-host overlay. Cancel: Esc now reliably stops a run. The web app SIGINTs the process group, then escalates to SIGKILL after a grace if it hasn't exited (some commands trapped SIGINT — /health never died). Grace is command-aware: terraform/ansible ops get a long runway to unwind gracefully; reads get a short one. health-check is also signal-aware (NotifyContext) so SIGINT cancels its context promptly. Co-Authored-By: Claude <noreply@anthropic.com>
- Unify model + API key into one gear settings panel (ALFRED-style); show the model name in the AGENT header (click → settings). - RANGE header: orange label + labeled identity fields (env / provider / region) pulled from the session. - DC tile icon → 🌐 (globe); connection indicator is now a colored dot (green/amber/red) like ALFRED; "agent working" uses the braille spinner. - Empty state when no sessions; fix chat-input `>`/text alignment. Co-Authored-By: Claude <noreply@anthropic.com>
Render /instances as a structured table (instances_report event) instead of a greyed raw-JSON blob — mirrors the /health pipeline: raw lines are suppressed and the parsed array is surfaced with per-state color dots. UI: user messages get chat bubbles; the input auto-grows upward across lines; the command popup follows keyboard nav (scrollIntoView) and shows white descriptions; range header fields are larger with electric-blue labels; the redundant settings gear is dropped (open via the model name or the no-key indicator). Split heavy vendor libs into their own chunks so the build no longer trips the 500 kB warning. Co-Authored-By: Claude <noreply@anthropic.com>
…eports The surface is a console, not a web app — renamed the directory, the launcher (dreadgoad-web → dreadgoad-console), the env vars and the state root, with the old DREADGOAD_WEBAPP_* names kept as fallbacks and .dreadgoad/webapp/ migrated on first run. Range identity is now provider-neutral. The Go CLI reports `account` and `group` on lab status --json (AWS Reservation.OwnerId, Azure subscription + resource group from the ARM id), and the ingestion hook stores them at the snapshot top level. Filing an AWS account under an Azure-shaped key was the alternative, and it was already happening. /validate and /scrub return structured reports rendered in chat instead of raw CLI text, and /scrub now defaults to applying — someone typing "clean the box" means clean it, and a command that silently changed nothing was the more surprising behaviour. Pass 'dry' to preview. Also here: - fix a /health hang: Process.wait() blocks on inherited pipes, so the runner polls returncode and drains on a budget instead - cancel is reported as cancelled, not as "exit -2" - a WebSocket Origin check; browsers don't apply same-origin policy to handshakes, so any page could otherwise drive the console - elapsed-time counter on the working indicator, surviving a reload - RANGE header pills wrap rather than being clipped by the status block Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…hell /diagnose has never worked on this branch. It died on an undefined `data_path` before reaching a host, and behind that failure sat a playbook hardcoded to a different variant's domain names, AWS-only IP discovery, and a CLI verb that never opened the Azure bastion tunnel it would have needed. It cost a real troubleshooting cycle this week, so it and its playbook are deleted rather than repaired. /exec replaces it, built on RunCommandOnMultiple — the provider-agnostic path that `ssm run` and `runcmd run` already use, minus their provider gates. It goes through Azure Run Command / AWS SSM rather than WinRM, which is the point: it reaches a host whose WinRM listener is down, exactly when provision and health-check cannot connect at all. Host matching is deliberately stricter than the ssm/runcmd helper it sits beside. That one substring-matches, so `dc0` silently selects three DCs; for a verb that mutates, an ambiguous or unmatched token is an error and --hosts has no "all" default. The agent drives it with a PowerShell payload and a host list, never a raw cloud CLI, so both providers look the same to it and every invocation stays inside the event pipeline. prompts/exec.md carries what it can't infer: output is capped at 4096 bytes per stream, there is no dry run, host output is untrusted data from a range other agents attack, and /validate closes the loop after any change. Also here: - system.md gains region, variant name and CIDR, so the agent stops guessing at facts the config already knows. Hook-learned fields stay out: instructions render once and cache, so they would freeze empty. - absent snapshot fields render "(not set)" rather than the string "None", which read to the model as a real value. - summarize_exec flags stdout landing on the provider's cap, measuring before strip() — PowerShell output ends in a newline, so the common case was silently unflagged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
/exec claimed to reach hosts whose WinRM was down, and did not. AzureProvider.RunCommand goes over WinRM through the bastion tunnel, so the verb inherited the exact dependency it advertised avoiding and failed against the first genuinely wedged host it met — a live session shows it returning "winrm run on 10.1.1.7" while diagnosing a DC that had stopped answering on 5985. Execution now goes through provider.OutOfBandRunner (Azure Managed Run Command, AWS SSM), and a provider that doesn't implement it is refused rather than silently downgraded to an in-guest channel. RunCommand keeps the WinRM fast path for the fan-out callers that want it: validate, health-check, verify-trusts. Two further defects the same session exposed: - Success was counted as failure. exec compared Status against "Succeeded" while every provider in the tree emits "Success", so a healthy run would have reported "0 succeeded" and exited non-zero. Invisible until now only because the host under test never succeeded. - Windows PowerShell writes its fatal banner as UTF-16LE, which reached the model and the chat pane as "W i n d o w s P o w e r S h e l l". Decoded at the provider boundary, with the console repeating the check since it can be pointed at an older CLI binary than it shipped with. /restart <host> exposes `lab restart-vm`, which existed in the CLI but not the registry — so the agent inspected /stop and /start, found no per-host flag, and told the operator a single-host reboot was impossible. It is the fix when a host is too wedged to repair from the inside. RangeView node spacing was derived from HostNode's maxWidth, which is the content box; the rendered node is 26px wider, so neighbours overlapped by 16px and adjacent tiers by 8px. Spacing now comes from the border box with a 28px gutter, and the hostname and role lines are clamped to one line — unclamped they wrapped past the height the tier spacing assumes, which is what made the bound false rather than merely tight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…troy error Three unrelated pieces of my own work; the backend changes in the tree belong to another session and are deliberately left unstaged. infra destroy reported "infra working directory not found", which reads as "recreate the directory". Terraform state here is local and gitignored, so a recreated directory starts from EMPTY state and would plan to CREATE the range a second time rather than tear down the running one. An operator following that hint goes looking for a directory that would not have helped while the resources keep billing — which is what happened. The error now says the state is missing, why recreating it won't help, and where to go instead. It is action-aware: a first apply has no state by definition and keeps the old scaffolding guidance, while destroy on a scaffolded-but-never-applied directory is now refused too rather than running and quietly doing nothing. /help explains a range run end to end — deploy, verify, validate, fix, score, reset, tear down — and renders in an empty chat pane so a new session opens on the workflow instead of a blank screen. Command descriptions come from the live registry rather than being written out again, so a renamed command can't leave the guide lying. It is client-side: it maps to no CLI verb, and the agent should not be able to "run" a guide. The range header cost two rows because spacing came from a segmented pill that puts the label beside the value — "RESOURCE GROUP" spent ~110px before its value began. Stacking the label above reclaims that for ~4px of height, and provider/region merge into one field since neither is useful alone. Measured max-content: 519px for a normal Azure range, so one row from ~700px up; a legal 90-char resource group still wraps, and truncates rather than escaping the panel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…24749 Frontend polish plus one test fix. The backend files here are another session's code; my changes to them are formatting and test-only, noted below. The "Agent working" label now carries a shimmer: a bright band clipped to the glyphs and swept left to right. Only background-position moves per frame, so nothing lays out or composites. The colour and opacity moved out of the component's inline style, where an inline `color` would have beaten the gradient outright and an inline `opacity` would have faded the highlight along with the base, flattening the sweep. Chrome and Safari paint -webkit-text-fill-color over `color`, so that is cleared too or the glyphs stay opaque and hide the gradient — and the braille spinner, a ::before, restates the fill colour so it stays steady against the sweeping label. Reduced motion drops the gradient as well as the animation: frozen, the band parks over one end of the label and reads as a rendering fault. The AGENT and RANGE banners sit at the top of the split and read as one bar, but were misaligned by exactly one pixel — box-sizing is border-box globally, so RANGE's 1px bottom border pushed it to 51 while AGENT sat on 50. Both now share --dg-pane-header-h, as minHeight so the range header can still grow when its fields wrap. A new session opens on the workflow guide, which is taller than the pane, so following the transcript to the end landed the reader on its last line. The pane now pins to the top while it holds only the guide and resumes following as soon as a turn produces output. Port 7331 becomes 24749 == 0x60AD, "GOAD" in hex. Outside the Linux ephemeral range (32768-60999) so the bind never races an outbound connection, and unregistered with IANA. test_cancelled_command_aborts_turn_before_agent_can_retry failed on roughly half of all runs. FakeRC separates its lines with sleep(0), so all 100 drain inside a single turn of the loop and the command joins and leaves `running` almost instantaneously; whether the poll caught that window came down to how many loop turns the dispatch path happened to take. Widening the poll's delay alone made it fail every time, which is what identified the cause. A local subclass with a real per-line delay holds the command in `running` until the test cancels it — the state actually under test. The neighbouring poll gets a real delay too; its fake blocks, so it cannot overshoot. Remaining backend edits are ruff format only, and two assertions that pin dispatch's `Task | None` contract instead of awaiting it blindly. console/backend/cli.py and sessions.py are also unformatted but are left alone — no other change here touches them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Destroy now prompts "Type 'yes' to confirm" in Go, then always passes --auto-approve to Terragrunt/OpenTofu, eliminating the downstream prompt that hangs on EOF in non-interactive contexts (console, CI, piped input). A --timeout flag (default 20 min) wraps the subprocess context so stuck CustomScriptExtension deletes are detected and reported with the last 20 lines of output. The up command forwards the flag with a 0 (no limit) default so TestUpInfraCommandForwardsEveryFlag remains green. Co-Authored-By: Claude <noreply@anthropic.com>
Wire `dreadgoad score generate-key` into both session creation paths so the agent has an answer key in its sandbox from the start. Previously the key was never generated, leaving agents unable to score until someone manually ran the CLI command. Co-Authored-By: Claude <noreply@anthropic.com>
The groups_domains role adds cross-domain members immediately after trusts are created, but the Netlogon secure channel that backs cross-domain LDAP auth can take well past the task's 3-retry budget (~3 min) to finish establishing — especially on Azure with WinRM/PSRP over Bastion. This surfaces as "server has rejected the client credentials" on Get-ADUser -Server <peer-domain>, which looks like a permissions problem but is actually a not-yet-ready condition. Add an nltest /sc_query gate that polls each peer domain's secure channel (retries: 30, delay: 20s, ~10 min budget) before attempting the cross-domain adds. Also bump the add task's own retries from 3→5 as a safety net for channels that pass nltest but still fail on the first authenticated LDAP call. Co-Authored-By: Claude <noreply@anthropic.com>
- scaffold.generate_answer_key: early-return when anchor has no config_path instead of passing str(None) to --config - agent.create_agent: raise ValueError when session_dir is absent instead of silently sandboxing writes to the project root - ruff format fixes for hostdetail.py, test_chat.py, test_hostdetail.py Co-Authored-By: Claude <noreply@anthropic.com>
Backend: consolidate Capture type into cli.py, replace _suppress with
contextlib.suppress, remove frozen DEFAULT_MODEL, fix _runner exception
handler, move WebSocket unregister to finally, fix extension node fields,
fix test import namespaces, clean up __import__("re").
Frontend: fix RangeView/App.tsx race conditions with cancelled-signal
pattern, fix CopyableCommand timer leak, extract shared Modal component
from 4 duplicated sites (backdrop, escape, stopPropagation).
Co-Authored-By: Claude <noreply@anthropic.com>
CopyableCommand: deduplicate the copy-to-clipboard textarea from ConnectModal (CommandField) and RangeView (CopyableCommand) into a shared component with compact/full visual modes. NewSessionModal + FormFields: move the 426-line NewSessionModal and the shared Field/Select/btnStyle helpers out of App.tsx (897 → 366 lines) so each module has a single concern. Progress cap: keep at most 200 consecutive command_progress lines per run in the message array — a sliding window that drops the oldest lines as new ones arrive. These events are already ephemeral (persist=False) and were the only unbounded growth vector. Co-Authored-By: Claude <noreply@anthropic.com>
- Prune events table (keep 2000) and cap replay to 500 chat events - Rotate backup files, keeping only the 5 most recent - Stabilise React keys on history replay using server-assigned seq - Track and clear autoScroll / WebSocket reconnect timers on unmount - Extract duplicate shortId/shortName to shared shortResourceId - Fix module-level env var pollution between test files - Clean up temp DB files in test teardown - Remove unused RangeEdge type Co-Authored-By: Claude <noreply@anthropic.com>
/copy [N|all] copies the last N agent messages to the clipboard, client-side only. /status runs /instances then /health in one agent turn so the operator doesn't have to type both. Co-Authored-By: Claude <noreply@anthropic.com>
Static scoring misses live_auth credentials (password resets, shadow credentials) — the agent kept omitting the flag because the prompt listed it as optional rather than default. Co-Authored-By: Claude <noreply@anthropic.com>
Resolve the test and Go module conflicts while retaining the feature branch's variant coverage and main's dependency updates.
There was a problem hiding this comment.
Pull request overview
Adds the agentic web console and strengthens cross-cloud provisioning, diagnostics, lifecycle management, and recovery.
Changes:
- Adds the FastAPI/React console with persistent sessions, topology, streaming commands, and reports.
- Introduces provider-neutral execution, report fetching, Azure capacity checks, and safer infrastructure lifecycle handling.
- Improves inventory repair, variant generation, retries, and Windows provisioning reliability.
Reviewed changes
Copilot reviewed 119 out of 188 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Ignores console and generated artifacts. |
console/backend/* |
Implements console APIs, persistence, synchronization, prompts, and runtime lifecycle. |
console/backend/tests/* |
Tests command cancellation and report fetching. |
console/frontend/* |
Implements the React console, shared components, state handling, and tests. |
docs/mkdocs/docs/* |
Documents exec and removes diagnose. |
cli/cmd/* |
Adds execution, fetching, capacity, inventory, environment, and infrastructure behavior. |
cli/internal/* |
Extends providers, Azure capacity checks, retries, configuration, and output normalization. |
cli/go.mod |
Promotes mapstructure to a direct dependency. |
modules/terraform-azure-* |
Updates Kali bootstrap and Windows extension execution. |
modules/terraform-aws-kali/* |
Installs attack-box tooling. |
infra/goad-deployment/* |
Aligns AWS deployment names and tags. |
infra/azure/goad-deployment/* |
Aligns Azure names, tags, and bootstrap paths. |
ansible/roles/* |
Improves PowerShell module installation and trust recovery. |
ansible/plugins/modules/win_ad_object.ps1 |
Handles nullable AD attributes safely. |
ad/GOAD*/scripts/* |
Normalizes constrained-delegation attribute values. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Correct provider-aware state checks, preserve command cancellation, harden console lifecycle behavior, and tighten Windows bootstrap and retry handling.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 120 out of 189 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
console/backend/prompts/up.md:19
--from infraresumes the pipeline at infra and then continues through provisioning and health-check; it does not “just redo infra.” This guidance can make the agent rerun every playbook when the operator explicitly requested an infra-only action. Describe it as “resume from infra” and state that infra-only work must useinfra applydirectly.
console/backend/prompts/exec.md:58- This recovery advice power-cycles the entire range, even though
/exectargets individual hosts and the newly added/restart <host>command exists specifically for one wedged VM. Following the prompt could unnecessarily take every domain controller and server offline. Recommend/restart <host>here.
Remove decoded Azure bootstrap scripts even when execution fails and correct agent guidance for infra-only work and targeted host recovery.
|
Addressed the two actionable prompt findings from Copilot’s follow-up review in |
…nd context - /secure: network security audit (NSGs, public IPs, bastion) with live progress, structured report, and SecurityChecker provider interface - ConfirmModal: replace all window.confirm() with DreadGOAD-themed modal dialogs for /destroy, session delete, cancel, and unverified commands - Direct command thread injection: append a [System: ...] note to the agent thread when operators run commands directly, so the LLM knows what happened between its turns; system prompt updated to explain this Co-Authored-By: Claude <noreply@anthropic.com>
After /destroy, inventory sync marks hosts as absent but left the health field at its last value — so destroyed VMs showed "healthy". Co-Authored-By: Claude <noreply@anthropic.com>
Adds an agentic browser workflow while hardening the CLI and cloud paths it drives.
Added
exec, report fetching, structured status and health output, and per-host lifecycle controls.Changed
Breaking
diagnoseis removed; useexec --hosts <hosts> --cmd <script>for control-plane diagnostics and recovery.infra destroynow confirms and defaults to a 20-minute timeout; automation must pass--auto-approveand may pass--timeout 0for no limit.upnow deploys the billed Bastion and controller prerequisites; useinfra applydirectly when managing a custom subset.dreadgoadinstead ofgoad; keep existing environment and state naming aligned before applying.Fixed