chore: bootstrap lean sysadmin-chronicles repo
Import the runnable game code, content, docs, scripts, and repo guidance while leaving local agent state, dependency installs, build output, and backup copies out of the published tree.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"id": "Q003",
|
||||
"title": "The Log That Ate the Disk",
|
||||
"tier": 1,
|
||||
"primary_vm": "web_server",
|
||||
"required_vms": ["workstation", "web_server"],
|
||||
"ticket_id": "T003",
|
||||
"baseline_snapshot": "baseline.clean",
|
||||
"summary": "logrotate is installed but the nginx config for it was accidentally deleted. The access log has grown to fill most of the disk. The player needs to identify the disk pressure, find the cause, clean up the log safely, and restore log rotation. A simple 'rm the log' solution works short-term but sets up a repeat. The proper fix restores the logrotate config.",
|
||||
"clue_fingerprint": {
|
||||
"description": "df -h shows / near capacity. du on /var/log/nginx shows an enormous access.log. /etc/logrotate.d/nginx is absent. The system logrotate timer ran last night and skipped nginx because the config was missing.",
|
||||
"evidence": [
|
||||
{ "type": "disk_usage_above", "vm": "web_server", "path": "/", "threshold_percent": 90 },
|
||||
{ "type": "file_size_above", "vm": "web_server", "path": "/var/log/nginx/access.log", "threshold_bytes": 2000000000 },
|
||||
{ "type": "file_absent", "vm": "web_server", "path": "/etc/logrotate.d/nginx" }
|
||||
]
|
||||
},
|
||||
"objectives": [
|
||||
{
|
||||
"id": "disk-pressure-resolved",
|
||||
"description": "Free disk space to below 70% utilization",
|
||||
"check_mode": "passive",
|
||||
"validation": {
|
||||
"type": "disk_usage_below",
|
||||
"vm": "web_server",
|
||||
"path": "/",
|
||||
"threshold_percent": 70
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "nginx-still-running",
|
||||
"description": "Nginx must remain operational throughout",
|
||||
"check_mode": "passive",
|
||||
"validation": {
|
||||
"type": "service_state",
|
||||
"vm": "web_server",
|
||||
"service": "nginx",
|
||||
"state": "active"
|
||||
}
|
||||
}
|
||||
],
|
||||
"solution_branches": [
|
||||
{
|
||||
"id": "logrotate-restored",
|
||||
"label": "Proper Fix — Rotation Restored",
|
||||
"priority": 100,
|
||||
"validation": {
|
||||
"type": "and",
|
||||
"rules": [
|
||||
{ "type": "disk_usage_below", "vm": "web_server", "path": "/", "threshold_percent": 70 },
|
||||
{ "type": "file_exists", "vm": "web_server", "path": "/etc/logrotate.d/nginx" },
|
||||
{ "type": "file_contains", "vm": "web_server", "path": "/etc/logrotate.d/nginx", "contains": "rotate" },
|
||||
{ "type": "service_state", "vm": "web_server", "service": "nginx", "state": "active" }
|
||||
]
|
||||
},
|
||||
"trust_delta": 3,
|
||||
"world_flags": ["hermes_logrotate_healthy", "hermes_disk_healthy"],
|
||||
"follow_up_dialogue": "marcus-Q003-complete-clean",
|
||||
"follow_up_ticket": "T004"
|
||||
},
|
||||
{
|
||||
"id": "log-truncated-only",
|
||||
"label": "Quick Fix — Log Cleared, No Rotation",
|
||||
"priority": 50,
|
||||
"validation": {
|
||||
"type": "and",
|
||||
"rules": [
|
||||
{ "type": "disk_usage_below", "vm": "web_server", "path": "/", "threshold_percent": 70 },
|
||||
{ "type": "service_state", "vm": "web_server", "service": "nginx", "state": "active" }
|
||||
]
|
||||
},
|
||||
"trust_delta": 0,
|
||||
"world_flags": ["hermes_disk_healthy", "hermes_log_pressure_pending"],
|
||||
"follow_up_incident": "I001",
|
||||
"follow_up_dialogue": "marcus-Q003-complete-norotate",
|
||||
"follow_up_ticket": "T004",
|
||||
"_note": "Disk is clear but rotation is not restored. I001 triggers in a few in-game hours and fills the disk again."
|
||||
},
|
||||
{
|
||||
"id": "nginx-killed",
|
||||
"label": "Collateral — Nginx Down",
|
||||
"priority": 200,
|
||||
"validation": {
|
||||
"type": "service_state",
|
||||
"vm": "web_server",
|
||||
"service": "nginx",
|
||||
"state": "inactive"
|
||||
},
|
||||
"trust_delta": -3,
|
||||
"world_flags": ["hermes_web_down", "hermes_disk_healthy"],
|
||||
"follow_up_dialogue": "sarah-Q003-angry",
|
||||
"follow_up_dialogues": ["marcus-Q003-complete-down"],
|
||||
"_note": "Player freed disk by stopping nginx (or deleted the wrong thing). Disk may be clear but the site is down again. Negative branch — should be rare but possible."
|
||||
}
|
||||
],
|
||||
"pressure_profile": "disk_growth_slow",
|
||||
"blast_radius": ["I001"],
|
||||
"unlock_requirements": ["world_flag:player_ssh_configured"],
|
||||
"narrative_phase": "normal_work",
|
||||
"linux_concepts": ["logrotate", "disk usage", "df", "du"],
|
||||
"failure_conditions": ["disk still above threshold", "logrotate not restored", "nginx not running"],
|
||||
"behavior_impact": {
|
||||
"default": { "curiosity_delta": 0, "obedience_delta": 1, "risk_delta": 0, "suspicion_delta": 0 }
|
||||
},
|
||||
"hidden_hook": null,
|
||||
"access_requirements": {
|
||||
"minimum_access": { "web_server": "sudo" },
|
||||
"requires_root": false,
|
||||
"temporary_grants_allowed": []
|
||||
},
|
||||
"tags": ["disk", "logs", "logrotate", "nginx", "web_server"],
|
||||
"internal_notes": "This quest teaches df, du, and logrotate. The clue trail is natural — disk alert, find the big file, notice logrotate is not configured. A good player restores the logrotate config from the package default or writes a correct one. A fast player just deletes the log. Both work short-term. The incident I001 makes the fast solution a problem later."
|
||||
}
|
||||
Reference in New Issue
Block a user