Skip to content
Merged

dev #236

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d198fc0
Fix corrupted TLS config
Brad-Edwards Mar 8, 2026
664cb2e
Fix ReDos
Brad-Edwards Mar 9, 2026
8f2f20c
Merge pull request #208 from Brad-Edwards:Brad-Edwards/issue183
Brad-Edwards Mar 9, 2026
54370db
Fix environ load fail causes fallback to lost telemetry
Brad-Edwards Mar 9, 2026
1ca29af
Fix tests fail to check collectors properly
Brad-Edwards Mar 9, 2026
af29776
Merge dev
Brad-Edwards Mar 9, 2026
9334c63
Merge pull request #210 from Brad-Edwards:184-run-assembly-does-not-l…
Brad-Edwards Mar 9, 2026
5bc26d6
Merge remote-tracking branch 'origin/dev' into 189-persistent-ssh-ses…
Brad-Edwards Mar 9, 2026
cad54a7
Fix stranded ssh sessions
Brad-Edwards Mar 9, 2026
fc94df7
Create test coverage for ts
Brad-Edwards Mar 9, 2026
37eaf46
Update serena config
Brad-Edwards Mar 20, 2026
e7c85a2
Generate coverage for SonarCloud
Brad-Edwards Mar 20, 2026
65aac73
Fix SonarCloud duplicate indexing of MCP test files
Brad-Edwards Mar 20, 2026
d175658
Add mgh workflow skill
Brad-Edwards Mar 20, 2026
dc7f0a8
Upgrade CI actions to Node.js 24 and migrate SonarCloud scanner
Brad-Edwards Mar 20, 2026
7b62c25
Merge pull request #211 from Brad-Edwards/189-persistent-ssh-sessions…
Brad-Edwards Mar 20, 2026
89d3633
ADR catchup
Brad-Edwards Mar 20, 2026
57bce35
Merge pull request #218 from Brad-Edwards/217-document-adrs
Brad-Edwards Mar 20, 2026
1873e1a
Notebook UI for range ops
Brad-Edwards Mar 20, 2026
00e8eff
Fix CI SonarCloud failure: install web deps for API tests
Brad-Edwards Mar 20, 2026
b491f96
Improve test coveragE
Brad-Edwards Mar 20, 2026
e15c556
Harden web UI: logging, di, sse, docker security
Brad-Edwards Mar 20, 2026
bbecc17
Run svelte-kit sync before web frontend tests
Brad-Edwards Mar 20, 2026
8f99855
Add missing dependencies and update skills
Brad-Edwards Mar 21, 2026
93f13d4
Coverage, security rating, pydantic v2.11 deprecation
Brad-Edwards Mar 21, 2026
6bf4b31
Fix security hotspots
Brad-Edwards Mar 21, 2026
8cef98b
rewrite lcov paths and add store tests
Brad-Edwards Mar 21, 2026
fc04b3a
Remove user controlled data from log statements
Brad-Edwards Mar 21, 2026
d3897f5
Merge pull request #220 from Brad-Edwards/219-sys-010-notebook-style-…
Brad-Edwards Mar 21, 2026
39d94ac
Add in browser terminal access
Brad-Edwards Mar 21, 2026
9fccc91
Review and security review fixes
Brad-Edwards Mar 21, 2026
6f7813b
Merge pull request #222 from Brad-Edwards/221-ui-003-xtermjs-terminal…
Brad-Edwards Mar 21, 2026
bdb69df
Add interactive scenario workbench UI
Brad-Edwards Mar 21, 2026
20e5999
Address implementation issues
Brad-Edwards Mar 21, 2026
49212f4
Remediate cross-origin vulns
Brad-Edwards Mar 21, 2026
79130e8
Fix code issues and test failures
Brad-Edwards Mar 21, 2026
47beb82
Update skill based on usage
Brad-Edwards Mar 21, 2026
2a3caa8
Merge pull request #224 from Brad-Edwards/223-ui-001-interactive-scen…
Brad-Edwards Mar 21, 2026
6393c96
Migrate to OTEL integration for interop
Brad-Edwards Mar 21, 2026
7339318
Fix review issues for security, unused, imports, span_id, consistency
Brad-Edwards Mar 21, 2026
c21c21a
Move Grafana creds to .env
Brad-Edwards Mar 21, 2026
f3acf96
Fix TS telemetry tests failing because no OTel collector
Brad-Edwards Mar 21, 2026
8821b13
Merge pull request #226 from Brad-Edwards/225-obs-001-opentelemetry-i…
Brad-Edwards Mar 21, 2026
09ebf8e
Update docs re kill switch
Brad-Edwards Mar 22, 2026
0d1b7c3
Fixes from code review
Brad-Edwards Mar 22, 2026
903bc3c
Merge pull request #230 from Brad-Edwards/229-saf-001-kill-switch-for…
Brad-Edwards Mar 22, 2026
45437ab
Add egress controls on Docker networks to reudce risks of range escape
Brad-Edwards Mar 22, 2026
95ace81
Fix potential breaking lab change and security risks
Brad-Edwards Mar 22, 2026
cf59898
Merge pull request #232 from Brad-Edwards/231-saf-002-network-egress-…
Brad-Edwards Mar 22, 2026
29d3aa6
Add deployment backend abstraction layer
Brad-Edwards Mar 22, 2026
3cc4743
Fixes after review
Brad-Edwards Mar 22, 2026
0d7832f
Merge pull request #234 from Brad-Edwards/233-dep-001-cloud-native-de…
Brad-Edwards Mar 22, 2026
0aac5ad
Add research/ to .gitignore
Brad-Edwards Mar 22, 2026
398a86f
Enable tailscale deployment
Brad-Edwards Mar 22, 2026
5b49677
Fix ssh commands for deploy
Brad-Edwards Mar 22, 2026
e4d26ad
Update deployment profile
Brad-Edwards Mar 22, 2026
da43031
Use shallow git clone to avoid large downloads
Brad-Edwards Mar 22, 2026
817c01b
Update serena config
Brad-Edwards Mar 24, 2026
f3ab00a
Fix deploy breaks on target without gh cli
Brad-Edwards Mar 24, 2026
48f8a70
Multiple fixes and security improvements
Brad-Edwards Mar 25, 2026
accc366
Update changelog
Brad-Edwards Mar 25, 2026
26686ea
Fix test helpers and SonarCloud integration
Brad-Edwards Mar 26, 2026
5990bb0
Deploy fixes
Brad-Edwards Mar 26, 2026
79c1e26
Fix deploy workflow
Brad-Edwards Mar 26, 2026
a42d70f
Additional deploy fixes
Brad-Edwards Mar 26, 2026
3227f0c
Additional deploy fixes
Brad-Edwards Mar 26, 2026
de03445
Deploy sequence updated for reliability
Brad-Edwards Mar 26, 2026
591c7e4
Change deploy method
Brad-Edwards Mar 26, 2026
1c527cd
Fix deployment IP collision
Brad-Edwards Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .claude/skills/gh-workflow-monitor/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: gh-workflow-monitor
description: Monitor GitHub workflows, propose fixes for failures, and report status
disable-model-invocation: true
---

# GitHub Workflow Monitor

Use the `gh` for GitHub operations.

## Step 1: Check current branch.

## Step 2: If the branch is not green, find the GitHub Actions workflow run associated with the current branch. Use the gh cli.

## Step 3: Monitor the workflow run for failures.

## Step 4: If the workflow run fails, propose a fix.

## Step 5: If the workflow run succeeds, exit plan mode and report the status.
52 changes: 52 additions & 0 deletions .claude/skills/implement/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: implement
description: Assess and implement a Ground Control requirement, ensuring GitHub issue and traceability links exist
argument-hint: <requirement-uid>
disable-model-invocation: true
---

# Implement Requirement: $ARGUMENTS

## Step 1: Fetch Requirement and Ensure GitHub Issue Exists

1. Enter plan mode.

2. Use the `gc_get_requirement` MCP tool with uid `GC-$ARGUMENTS` to fetch the requirement details. Note the requirement's UUID, title, statement, status, and wave.

3. Use the `gc_get_traceability` MCP tool with the requirement's UUID to check for existing traceability links. Look for a link with artifact_type `GITHUB_ISSUE`.

4. If NO GitHub issue link exists:
- Use the `gc_create_github_issue` MCP tool with uid `$ARGUMENTS` to create a GitHub issue and auto-link it.

5. If a GitHub issue link DOES exist, note the issue number from the artifact_identifier.

6. Run `gh issue develop <issue-number> --checkout --base dev` to switch to the issue branch.

## Step 2: Read the GitHub Issue

Run `gh issue view <issue-number>` to read the full issue details including description, labels, and comments.

## Step 3: Assess Codebase Coverage

Explore the codebase to determine whether the requirement described in the issue is already satisfied by existing code:
- Search for relevant classes, methods, tests, and configurations
- Check if the described behavior already exists
- Review any existing traceability links (IMPLEMENTS, TESTS) from Step 1

## Step 4: Plan or Report

- **If the requirement is NOT yet met**: Plan the implementation. Identify which files need to be created or modified, what tests to write, and what approach to take. Enter plan mode.
- Your plans must respect the coding standards and classification levels in ADR-012.
- Plans must include updating the changelog, readme, and docs as appropriate.
- **If the requirement IS already met**: Report that the requirement is satisfied and identify which code satisfies it.

## Step 5: Ensure Traceability Links

After implementation is complete (or if already implemented):
- use the `gc_create_traceability_link` MCP tool to create any missing links:
- `IMPLEMENTS` links from the requirement to the code files that implement it
- `TESTS` links from the requirement to the test files that verify it
- Only create links that don't already exist (check the traceability data from Step 1).
- use the `gc_transition_status` MCP tool to transition the requirement to `ACTIVE` if it was `DRAFT`.

Do not update the Changelog if all you did was operate Ground Control tools.
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.git
.github
.venv
.pytest_cache
.mypy_cache
__pycache__
*.pyc
node_modules
containers/
docs/
notes/
coverage.xml
.coverage
*.egg-info
dist/
build/
.svelte-kit
web/node_modules
web/.svelte-kit
web/tests
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ MISP_ADMIN_PASSWORD=MispAdmin2024!
THEHIVE_SECRET=aptl-thehive-lab-secret-key-2024-purple
SHUFFLE_ADMIN_PASSWORD=ShuffleAdmin2024!
SHUFFLE_API_KEY=31a211c4-ea5c-4a49-b022-5e2434e758a7

# Grafana (OTel observability stack)
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=CHANGE_ME_grafana_password
139 changes: 139 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Deploy Lab

on:
push:
branches: [dev]
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
type: environment
required: true

jobs:
deploy:
# On push to dev: use DEFAULT_DEPLOY_ENVIRONMENT repo variable.
# On manual dispatch: use the selected environment.
# If neither exists, the job is skipped entirely — users who
# only run locally are unaffected.
environment: ${{ inputs.environment || vars.DEFAULT_DEPLOY_ENVIRONMENT }}
if: ${{ inputs.environment || vars.DEFAULT_DEPLOY_ENVIRONMENT != '' }}
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Connect to Tailscale
if: vars.DEPLOY_VIA_TAILSCALE == 'true'
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci

- name: Set up SSH
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key

- name: Deploy
env:
DEPLOY_HOST: ${{ vars.DEPLOY_HOST }}
DEPLOY_USER: ${{ vars.DEPLOY_USER }}
DEPLOY_DIR: ${{ vars.DEPLOY_DIR || '/opt/aptl' }}
DEPLOY_SSH_PORT: ${{ vars.DEPLOY_SSH_PORT || '22' }}
run: |
SSH="ssh -i ~/.ssh/deploy_key -p ${DEPLOY_SSH_PORT} -o StrictHostKeyChecking=accept-new ${DEPLOY_USER}@${DEPLOY_HOST}"

# Stop any running lab before syncing code
$SSH "cd ${DEPLOY_DIR} && docker stop \$(docker ps -q) 2>/dev/null; docker rm \$(docker ps -aq) 2>/dev/null; docker network prune -f 2>/dev/null; true"

# Sync repo from runner to remote (runner has repo access, remote doesn't)
$SSH "mkdir -p ${DEPLOY_DIR}"
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -p ${DEPLOY_SSH_PORT} -o StrictHostKeyChecking=accept-new" \
--exclude='.git' \
--exclude='.env' \
--exclude='config/wazuh_indexer_ssl_certs' \
--exclude='tools/misp-mcp-server' \
--exclude='.venv' \
--exclude='keys' \
--exclude='runs' \
--exclude='.aptl' \
--exclude='node_modules' \
./ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_DIR}/"

# Seed .env from example if first deploy
$SSH "cd ${DEPLOY_DIR} && [ -f .env ] || cp .env.example .env"

# Install Python CLI in venv and start lab
$SSH "cd ${DEPLOY_DIR} && ([ -d .venv ] || python3 -m venv .venv) && .venv/bin/pip install -e ."
$SSH "cd ${DEPLOY_DIR} && .venv/bin/aptl lab start"

- name: Verify
env:
DEPLOY_HOST: ${{ vars.DEPLOY_HOST }}
DEPLOY_USER: ${{ vars.DEPLOY_USER }}
DEPLOY_DIR: ${{ vars.DEPLOY_DIR || '/opt/aptl' }}
DEPLOY_SSH_PORT: ${{ vars.DEPLOY_SSH_PORT || '22' }}
run: |
SSH="ssh -i ~/.ssh/deploy_key -p ${DEPLOY_SSH_PORT} -o StrictHostKeyChecking=accept-new ${DEPLOY_USER}@${DEPLOY_HOST}"

# Poll until all containers are running (12 attempts x 10s = 120s max)
for attempt in $(seq 1 12); do
echo "Verify attempt ${attempt}/12..."
RESULT=$($SSH "cd ${DEPLOY_DIR} && docker compose ps --format json" 2>/dev/null || echo "")

if [ -n "$RESULT" ]; then
STATUS=$(echo "$RESULT" | python3 -c "
import json, sys
containers = []
for line in sys.stdin:
line = line.strip()
if not line: continue
try:
if line.startswith('['):
containers.extend(json.loads(line))
else:
containers.append(json.loads(line))
except json.JSONDecodeError:
continue
if not containers:
print('WAITING')
sys.exit(0)
for c in containers:
name = c.get('Name', 'unknown')
state = c.get('State', 'unknown')
health = c.get('Health', '')
info = f' {name}: {state}'
if health: info += f' ({health})'
print(info, file=sys.stderr)
running = sum(1 for c in containers if c.get('State') == 'running')
total = len(containers)
print(f'{running}/{total} containers running', file=sys.stderr)
if running >= total:
print('PASS')
else:
print('WAITING')
")

if [ "$STATUS" = "PASS" ]; then
echo "All containers running."
exit 0
fi
fi

echo "Not ready yet, waiting 10s..."
sleep 10
done

echo "ERROR: Containers did not all reach running state within 120s"
exit 1

- name: Cleanup SSH key
if: always()
run: rm -f ~/.ssh/deploy_key
27 changes: 23 additions & 4 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,41 @@ jobs:
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
pip install -e ".[dev,web]"
- name: Run tests with coverage
run: |
coverage run -m pytest tests/ -q -k "not integration"
coverage xml -o coverage.xml
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
- name: Run MCP TypeScript tests with coverage
run: |
cd mcp/aptl-mcp-common
npm install
npx vitest run --coverage
- name: Run web frontend tests with coverage
run: |
cd web
npm install
npx svelte-kit sync
npx vitest run --coverage
sed -i 's|^SF:|SF:web/|' coverage/lcov.info
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@v5
uses: SonarSource/sonarqube-scan-action@v7
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.qualitygate.wait=true
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ downloads/
eggs/
.eggs/
lib/
!web/src/lib/
!web/tests/lib/
lib64/
parts/
sdist/
Expand Down Expand Up @@ -247,6 +249,9 @@ bower_components
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# SvelteKit generated
.svelte-kit/

# Dependency directories
node_modules/
jspm_packages/
Expand Down Expand Up @@ -396,4 +401,6 @@ config/wazuh_indexer_ssl_certs/*

notes/

research/

data/
8 changes: 4 additions & 4 deletions .mcp.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@
"command": "node",
"args": ["./mcp/mcp-red/build/index.js"],
"env": {
"APTL_TRACE_DIR": "./.aptl/traces"
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"
}
},
"reverse-sandbox-ssh": {
"command": "node",
"args": ["./mcp/mcp-reverse/build/index.js"],
"env": {
"APTL_TRACE_DIR": "./.aptl/traces"
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318"
}
},
"shuffle": {
"command": "node",
"args": ["./mcp/mcp-soar/build/index.js"],
"env": {
"APTL_TRACE_DIR": "./.aptl/traces",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318",
"SHUFFLE_API_KEY": "<run seed-shuffle.sh or check Shuffle UI>"
}
},
"indexer": {
"command": "node",
"args": ["./mcp/mcp-indexer/build/index.js"],
"env": {
"APTL_TRACE_DIR": "./.aptl/traces",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318",
"INDEXER_USERNAME": "admin",
"INDEXER_PASSWORD": "SecretPassword",
"API_USERNAME": "wazuh-wui",
Expand Down
19 changes: 19 additions & 0 deletions .serena/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,22 @@ language_backend:
# list of regex patterns which, when matched, mark a memory entry as read‑only.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []

# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:

# list of regex patterns for memories to completely ignore.
# Matching memories will not appear in list_memories or activate_project output
# and cannot be accessed via read_memory or write_memory.
# To access ignored memory files, use the read_file tool on the raw file path.
# Extends the list from the global configuration, merging the two lists.
# Example: ["_archive/.*", "_episodes/.*"]
ignored_memory_patterns: []

# advanced configuration option allowing to configure language server-specific options.
# Maps the language key to the options.
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
# No documentation on options means no options are available.
ls_specific_settings: {}
Loading
Loading