phase: 02_simulate_fetch_commands
Build and Push Container / build-and-push (push) Successful in 26s

All green. Final report:

**Phase 02 — final verification pass** (both tasks already in `.agents/phases/complete/02_simulate_fetch_commands/`)
- Verified: no `fetch(` remains in `src/` (grep exit 1) or in built `dist/*.js`
- Verified: `simulatedCurlOutput()` / `simulatedWgetOutput()` in `src/terminal-commands.js` (lines 63/73), wired into `src/terminal.js` curl/wget branches
- Verified: regression test `curl/wget are simulated — no real network request leaves the origin` in `tests/e2e/02-terminal.spec.js` — asserts simulated bodies, `web_navigator` toast + localStorage persistence, and zero non-`baseURL` requests
- Tests: `./build.sh` → OK; `npm test` → **46 passed, 0 failed** (≥46 required); `bash .agents/validate.sh` → **exit 0** (E2E + repo-hygiene gates)
- No linter configured beyond validate.sh (vanilla JS, LOCKED no-toolchain)
- Completion criteria: ①no `fetch(` ✅ ②simulators present ✅ ③regression tests present & passing ✅ ④build+test 46 green ✅ ⑤no behavior change (page/terminal/vim/achievements/menu suites all green) ✅
- Documentation: full README/AGENTS.md review — both already updated in working tree and consistent with the project (simulated curl/wget, validate.sh gate, Podman build flow vs Dockerfile, Node ≥20 matches `@playwright/test` engines, M-4 header gap correctly documented as pending Phase 03) — **verified consistent, no changes needed**
- Note: `PLAN.md` still says "44 tests" (now 46) but PLAN is locked — flagged for the harness/user, not edited
- Next pending phase: `03_nginx_security_headers`
This commit is contained in:
2026-10-22 23:14:49 -04:00
parent dcd066d953
commit bcfaa1cac6
21 changed files with 1423 additions and 21 deletions
+34
View File
@@ -51,3 +51,37 @@ function getCommandOutput(cmdText) {
if (value === undefined) return undefined;
return typeof value === 'function' ? value() : value;
}
// Simulated fetch output. The fake terminal performs NO real network I/O by
// design — these produce a deterministic, clearly-simulated response that
// echoes the requested URL (audit finding M-2: curl/wget used to fetch the
// unvalidated URL straight from the visitor's keyboard).
function _simulatedBody(url) {
return 'simulated body for ' + url;
}
function simulatedCurlOutput(url) {
const body = _simulatedBody(url);
return [
' % Total % Received % Xferd Average Speed Time Time Time Current',
' Dload Upload Total Spent Left Speed',
'100 ' + body.length + ' 100 ' + body.length + ' 0 0 ' + (body.length * 40) + ' 0 --:--:-- --:--:-- --:--:--',
body,
].join('\n');
}
function simulatedWgetOutput(url) {
const body = _simulatedBody(url);
return [
'-- ' + new Date().toISOString().replace('T', ' ').slice(0, 19) + '-- ' + url,
'Resolving host... (simulated)',
'Connecting... connected (simulated).',
'HTTP request sent, awaiting response... 200 OK',
'Length: ' + body.length + ' [text/plain]',
"Saving to: 'index.html'",
'',
body,
'',
'Finished (simulated). No real network request was made.',
].join('\n');
}
+10 -20
View File
@@ -379,16 +379,11 @@ function createTerminal(face) {
outLine.style.color = '#ccc';
outLine.textContent = 'Downloading...';
content.appendChild(outLine);
fetch(url)
.then(r => r.text())
.then(data => {
outLine.textContent = data;
content.scrollTop = content.scrollHeight;
})
.catch(err => {
outLine.textContent = 'curl: error fetching ' + url + ': ' + err.message;
content.scrollTop = content.scrollHeight;
});
// Simulated output — the fake terminal never performs real network I/O.
setTimeout(() => {
outLine.textContent = simulatedCurlOutput(url);
content.scrollTop = content.scrollHeight;
}, 400);
} else if (cmdText.startsWith('wget ')) {
const url = cmdText.replace(/^wget\s+(?:-O\s+\S+\s+)?/, '');
const outLine = document.createElement('div');
@@ -396,16 +391,11 @@ function createTerminal(face) {
outLine.style.color = '#ccc';
outLine.textContent = 'Downloading...';
content.appendChild(outLine);
fetch(url)
.then(r => r.text())
.then(data => {
outLine.textContent = data;
content.scrollTop = content.scrollHeight;
})
.catch(err => {
outLine.textContent = 'wget: error fetching ' + url + ': ' + err.message;
content.scrollTop = content.scrollHeight;
});
// Simulated output — the fake terminal never performs real network I/O.
setTimeout(() => {
outLine.textContent = simulatedWgetOutput(url);
content.scrollTop = content.scrollHeight;
}, 400);
} else if (cmdText.startsWith('apt ')) {
const pkg = cmdText.replace(/^apt\s+/, '');
const outLine = document.createElement('div');