Skip to content

feat: run offline demos for all scenarios - #10

Merged
Ker102 merged 2 commits into
mainfrom
feat/offline-scenario-runs
May 8, 2026
Merged

Ker102 merged 2 commits into
mainfrom
feat/offline-scenario-runs

Conversation

@Ker102

@Ker102 Ker102 commented May 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • make every scaffolded scenario runnable in offline demo mode
  • add deterministic findings/remediation for AWS S3, Kubernetes privileged pods, Docker Compose public admin ports, on-prem SSH baselines, and generic plan-only public admin ingress
  • add branded Nullstate CLI banner for demo recordings
  • update scenario metadata, docs, and tests

Evidence to capture before merge

  • PR branch/title/body with Closes #9
  • CI checks while pending and green
  • CodeRabbit review result
  • python -m nullstate doctor --offline banner output
  • one offline scenario run, for example compose-exposed-admin, showing success before and blocked after

Verification

  • python -m unittest discover -s tests -v
  • python -m ruff check src tests
  • python -m mypy src
  • python -m pip_audit . --skip-editable
  • python -m nullstate run examples/compose-exposed-admin --offline --target docker-compose --scenario compose-exposed-admin --runs-dir $env:TEMP\nullstate-compose-demo-run
  • python -m nullstate doctor --offline

Closes #9

Summary by CodeRabbit

  • New Features

    • Offline deterministic demos now available for AWS, Kubernetes, Docker Compose, on-prem, and generic plan-review scenarios.
    • Added branded CLI banner for improved demo recording experience.
    • Scenario-specific vulnerability detection and remediation workflows.
  • Documentation

    • Updated project scope to infrastructure-as-code sandboxes across multiple platforms.
    • Enhanced quickstart with offline scenario examples.
  • Tests

    • Added comprehensive end-to-end offline scenario validation tests.

@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Rate limit exceeded

@Ker102 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 18 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bee7eed3-f45d-4198-ad63-2e284d0ed392

📥 Commits

Reviewing files that changed from the base of the PR and between 45503c6 and b872a6d.

📒 Files selected for processing (1)
  • README.md
📝 Walkthrough

Walkthrough

This PR extends Nullstate to run offline deterministic demonstrations across five infrastructure scenarios (AWS S3, Kubernetes, Docker Compose, on-prem SSH, generic plan review) by implementing scenario-specific finding detection, targeted remediation logic, branded CLI output, and comprehensive test coverage—enabling the hackathon case study to showcase multiple attack paths beyond Azure.

Changes

Multi-scenario offline demo execution

Layer / File(s) Summary
Scenario metadata
src/nullstate/scenarios.py
Status strings for five scenarios updated from "scaffolded" to "offline demo available; live pending" messaging.
Scenario-specific finding detectors
src/nullstate/findings.py
Router function find_scenario_findings dispatches to six specialized detectors: S3 public access blocks, Kubernetes privilege escalation, Docker Compose port bindings, on-prem SSH auth, generic plan ingress, plus helpers for file globbing and recursive CIDR/port inspection.
Scenario-specific remediation
src/nullstate/remediation.py
Generalized remediate_scenario_files router applies per-scenario updaters: Azure storage block securing, AWS flag flipping, K8s privilege removal, Compose port binding tightening, on-prem SSH disabling, and JSON CIDR replacement via _replace_public_cidr.
Offline plan loading
src/nullstate/terraform.py
In offline mode, load_plan_json prefers pre-exported tfplan.json files; static_plan_from_tf now includes all resource types, not just Azure storage.
Demo scenario content
src/nullstate/demo.py, examples/generic-plan-review/
Generic plan review JSON populated with example firewall rule exposing 0.0.0.0/0 to port 22; scenario READMEs updated to "offline review" wording.
Scenario attack scripts
src/nullstate/attack.py
Replaces single ATTACK_SCRIPT constant with ATTACK_SCRIPTS dict keyed by scenario name; adds ATTACK_DETAILS rule-ID-to-detail mapping; write_attack_script and simulate_attack accept scenario parameter.
CLI scenario routing
src/nullstate/cli.py
Adds BANNER constant and _print_banner() helper; enforces offline mode for non-Azure scenarios; routes run command through find_scenario_findings and remediate_scenario_files; passes scenario name to attack script generation; updates summary language to "IaC exposure".
Report terminology
src/nullstate/report.py
Replaces "Terraform input" with "IaC input" and updates case study notes wording.
Package metadata
pyproject.toml
Description broadened from "Terraform Azure IaC" to "infrastructure-as-code sandboxes".
Documentation and examples
CHANGELOG.md, README.md, docs/architecture.md, docs/case-study.md, docs/runbook.md
Changelog adds offline demo and banner entries; README extends Hackathon V1 scope, adds quickstart examples for offline AWS/K8s runs, and updates scenarios table and status section; architecture roadmap and case study refined; runbook includes all offline scenario verification commands.
End-to-end test suite
tests/test_offline_scenario_runs.py
Validates doctor --offline banner output and iterates all offline scenarios: initializes demo, runs offline analysis, verifies findings match expected rule IDs, and confirms report/patch artifacts are non-empty.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Five paths now run in silence, no sandbox required,
S3 buckets, pods, and compose stacks—all inspired.
From plan to patch, each scenario finds its way,
A banner bold announces the purple-team's ballet.
No azure-only shackles—now the cli runs free!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: enabling offline demo runs for all scenarios, which is the primary objective of this changeset.
Description check ✅ Passed The description includes all major sections from the template with substantive content: a detailed summary, comprehensive verification steps, security checks, and documentation updates. The PR properly references issue #9.
Linked Issues check ✅ Passed All acceptance criteria from issue #9 are addressed: offline runs work for all five scenarios (AWS S3, K8s, Docker Compose, on-prem SSH, generic plan review), each produces required artifacts, a branded CLI banner is added, and comprehensive tests are included.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #9 objectives: scenario-specific findings and remediation implementations, CLI banner addition, demo helpers, test coverage, and documentation updates. No extraneous changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/offline-scenario-runs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/nullstate/report.py (1)

18-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stale "Terraform" fallback message missed by the IaC rename.

Lines 24 and 54 were updated, but the fallback text on line 18 still says "Terraform", so the rendered report will read "No Terraform changes were required." even though the rest of the report now uses "IaC".

🔧 Proposed fix
-    diff = patch_diff.strip() or "No Terraform changes were required."
+    diff = patch_diff.strip() or "No IaC changes were required."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/nullstate/report.py` at line 18, Update the stale fallback message used
when computing the diff: replace the hardcoded string "No Terraform changes were
required." with the IaC-consistent text (e.g. "No IaC changes were required.")
where the variable diff is assigned (refer to the diff = patch_diff.strip() or
... expression in src/nullstate/report.py) so the report text matches the
renamed terminology across the file.
src/nullstate/cli.py (1)

92-99: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Move plan-only offline coercion before the non-azure offline guard.

Line 92 checks not offline before Line 97 forces plan-only runs to offline mode. This makes --target plan-only fail for non-Azure scenarios unless users manually add --offline, even though the command already auto-coerces plan-only mode.

Suggested fix
-    if scenario_spec.name != "azure-public-blob" and not offline:
-        raise typer.BadParameter(
-            f"Scenario {scenario_spec.name!r} supports offline demo execution only for now. "
-            "Use --offline until its live sandbox adapter is implemented."
-        )
     if backend.mode == "plan-only":
         offline = True
+    if scenario_spec.name != "azure-public-blob" and not offline:
+        raise typer.BadParameter(
+            f"Scenario {scenario_spec.name!r} supports offline demo execution only for now. "
+            "Use --offline until its live sandbox adapter is implemented."
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/nullstate/cli.py` around lines 92 - 99, The guard that disallows
non-Azure scenarios when not offline is executed before the code that
auto-coerces plan-only runs to offline; move the plan-only coercion (the check
of backend.mode == "plan-only" setting offline = True) above the
scenario_spec.name != "azure-public-blob" and not offline check so that when
backend.mode is "plan-only" the offline flag is set first and the non-azure
offline guard sees offline=True; update the block that references backend.mode,
offline, and scenario_spec.name accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/nullstate/remediation.py`:
- Around line 98-104: _remediate_generic_plan_text is always reserializing the
JSON which causes spurious diffs even when _replace_public_cidr made no changes;
change it to compare the parsed payload to the updated result from
_replace_public_cidr and only call json.dumps(...) (and add the trailing
newline) when the updated object differs from the original payload, otherwise
return the original text unchanged so _remediate_files won't report
formatting-only changes.

In `@tests/test_offline_scenario_runs.py`:
- Around line 79-81: The test currently asserts the expected rule ID by indexing
findings[0], which is order-dependent and flaky; update the assertion to check
that any finding in the findings list has rule_id equal to expected_rule_id
(e.g., use an any(...) over findings comparing each finding["rule_id"] to
expected_rule_id) while keeping the existing assertTrue(findings) and
assertIn(expected_rule_id, report); locate the assertion using the symbols
findings and expected_rule_id in the test_offline_scenario_runs.py test and
replace the findings[0] equality check with an existence check across the list.

---

Outside diff comments:
In `@src/nullstate/cli.py`:
- Around line 92-99: The guard that disallows non-Azure scenarios when not
offline is executed before the code that auto-coerces plan-only runs to offline;
move the plan-only coercion (the check of backend.mode == "plan-only" setting
offline = True) above the scenario_spec.name != "azure-public-blob" and not
offline check so that when backend.mode is "plan-only" the offline flag is set
first and the non-azure offline guard sees offline=True; update the block that
references backend.mode, offline, and scenario_spec.name accordingly.

In `@src/nullstate/report.py`:
- Line 18: Update the stale fallback message used when computing the diff:
replace the hardcoded string "No Terraform changes were required." with the
IaC-consistent text (e.g. "No IaC changes were required.") where the variable
diff is assigned (refer to the diff = patch_diff.strip() or ... expression in
src/nullstate/report.py) so the report text matches the renamed terminology
across the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07ff74c0-4cae-4de6-8cec-9401369cc243

📥 Commits

Reviewing files that changed from the base of the PR and between d7e0801 and 45503c6.

📒 Files selected for processing (17)
  • CHANGELOG.md
  • README.md
  • docs/architecture.md
  • docs/case-study.md
  • docs/runbook.md
  • examples/generic-plan-review/README.md
  • examples/generic-plan-review/tfplan.json
  • pyproject.toml
  • src/nullstate/attack.py
  • src/nullstate/cli.py
  • src/nullstate/demo.py
  • src/nullstate/findings.py
  • src/nullstate/remediation.py
  • src/nullstate/report.py
  • src/nullstate/scenarios.py
  • src/nullstate/terraform.py
  • tests/test_offline_scenario_runs.py

Comment thread src/nullstate/remediation.py
Comment thread tests/test_offline_scenario_runs.py
@Ker102
Ker102 merged commit 51d88a6 into main May 8, 2026
5 checks passed
@Ker102
Ker102 deleted the feat/offline-scenario-runs branch May 8, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: run offline demos for all scaffolded scenarios

1 participant