@@ -737,7 +737,7 @@
${esc(i.title)}
// Load overview in background
api('GET', '/overview').then(ov => { state.overview = ov; render(); }).catch(() => {});
} catch (e) {
- alert('Fout bij laden workspaces: ' + e.message);
+ alert('Error loading workspaces: ' + e.message);
} finally {
state.loading = false; render();
}
@@ -774,7 +774,7 @@
${esc(i.title)}
setTimeout(() => openManageCredentials(), 100);
return;
}
- alert('Fout bij laden issues: ' + e.message);
+ alert('Error loading issues: ' + e.message);
} finally {
state.issueLoading = false; render();
}
@@ -886,22 +886,22 @@
${esc(i.title)}
async function doInject(issues, containerName) {
const msgEl = document.getElementById('inject-msg');
- if (msgEl) msgEl.innerHTML = `
`;
+ if (msgEl) msgEl.innerHTML = `
`;
try {
await api('POST', `/workspaces/${encodeURIComponent(state.selectedWs)}/inject`, {
container_name: containerName,
issues,
});
- if (msgEl) msgEl.innerHTML = `
✓ Context geïnjecteerd in ${esc(containerName)}. Voer aikido-fix uit in de container.
`;
+ if (msgEl) msgEl.innerHTML = `
✓ Context injected into ${esc(containerName)}. Run aikido-fix in the container.
`;
} catch (e) {
- if (msgEl) msgEl.innerHTML = `
Fout: ${esc(e.message)}
`;
+ if (msgEl) msgEl.innerHTML = `
Error: ${esc(e.message)}
`;
}
}
// ── Workspace modal ────────────────────────────────────────────────────────
function openAddWorkspace() {
state.editingWs = null;
- document.getElementById('ws-modal-title').textContent = 'Workspace toevoegen';
+ document.getElementById('ws-modal-title').textContent = 'Add workspace';
document.getElementById('ws-name').value = '';
document.getElementById('ws-prefix').value = '';
document.getElementById('ws-path').value = '';
@@ -917,7 +917,7 @@
${esc(i.title)}
const ws = state.workspaces.find(w => w.name === name);
if (!ws) return;
state.editingWs = ws;
- document.getElementById('ws-modal-title').textContent = `Workspace bewerken — ${name}`;
+ document.getElementById('ws-modal-title').textContent = `Edit workspace — ${name}`;
document.getElementById('ws-name').value = ws.name;
document.getElementById('ws-name').disabled = true;
document.getElementById('ws-prefix').value = ws.aikido_env_prefix;
@@ -941,7 +941,7 @@
${esc(i.title)}
const msg = document.getElementById('ws-modal-msg');
if (!name || !prefix || !rpath || !wsid || !lang) {
- msg.innerHTML = `
Alle verplichte velden zijn vereist.
`; return;
+ msg.innerHTML = `
All required fields are required.
`; return;
}
const body = { name, aikido_env_prefix: prefix, repo_path: rpath, workspace_id: wsid, language: lang, code_repo_name: repo || undefined };
@@ -986,14 +986,14 @@
${esc(i.title)}
const clientSecret = document.getElementById('cred-secret').value;
const msg = document.getElementById('cred-modal-msg');
if (!clientId || !clientSecret) {
- msg.innerHTML = `
Client ID en Secret zijn verplicht.
`; return;
+ msg.innerHTML = `
Client ID and Secret are required.
`; return;
}
try {
const res = await api('POST', `/credentials/${encodeURIComponent(state.credPrefix)}`, { client_id: clientId, client_secret: clientSecret });
if (res.validated) {
- msg.innerHTML = `
✓ Credentials opgeslagen en gevalideerd.
`;
+ msg.innerHTML = `
✓ Credentials saved and validated.
`;
} else {
- msg.innerHTML = `
Opgeslagen, maar validatie mislukt: ${esc(res.validation_error || 'onbekend')}
`;
+ msg.innerHTML = `
Saved, but validation failed: ${esc(res.validation_error || 'unknown')}
`;
}
await loadWorkspaces();
} catch (e) {
@@ -1002,7 +1002,7 @@
${esc(i.title)}
}
async function deleteCreds() {
- if (!confirm('Credentials verwijderen?')) return;
+ if (!confirm('Delete credentials?')) return;
try {
await api('DELETE', `/credentials/${encodeURIComponent(state.credPrefix)}`);
closeCredModal();
diff --git a/gateway/extensions/aikido/index.js b/gateway/extensions/aikido/index.js
index f3e53c2..e58108b 100644
--- a/gateway/extensions/aikido/index.js
+++ b/gateway/extensions/aikido/index.js
@@ -52,36 +52,36 @@ function generateClaudePrompt(issues, ws) {
const repoName = ws.code_repo_name || ws.name;
let issueSection;
if (issues.length === 1) {
- issueSection = `Kwetsbaarheid:\n${JSON.stringify(issues[0], null, 2)}`;
+ issueSection = `Vulnerability:\n${JSON.stringify(issues[0], null, 2)}`;
} else {
- issueSection = `Er zijn ${issues.length} kwetsbaarheden:\n\n` +
+ issueSection = `There are ${issues.length} vulnerabilities:\n\n` +
issues.map((i, n) => `### Issue ${n + 1}\n${JSON.stringify(i, null, 2)}`).join('\n\n');
}
- return `Je bent een senior security engineer gespecialiseerd in ${language.toUpperCase()} applicaties.
+ return `You are a senior security engineer specializing in ${language.toUpperCase()} applications.
-Fix de volgende ${issues.length === 1 ? 'kwetsbaarheid' : `${issues.length} kwetsbaarheden`} in deze codebase:
+Fix the following ${issues.length === 1 ? 'vulnerability' : `${issues.length} vulnerabilities`} in this codebase:
-## Beschikbare MCP Tools
+## Available MCP Tools
-| Tool | Beschrijving |
+| Tool | Description |
|------|-------------|
-| \`aikido_issues_list\` | Open issues ophalen (filter met \`repo_name: "${repoName}"\`) |
-| \`aikido_issue_details\` | Details van een specifiek issue |
-| \`aikido_scan_repo\` | Scan triggeren na een fix |
-| \`aikido_list_repos\` | Repositories ophalen |
-| \`aikido_ignore_issue\` | Issue negeren als false positive |
-| \`aikido_add_note\` | Notitie toevoegen aan een issue |
+| \`aikido_issues_list\` | Get open issues (filter with \`repo_name: "${repoName}"\`) |
+| \`aikido_issue_details\` | Get details of a specific issue |
+| \`aikido_scan_repo\` | Trigger scan after fix |
+| \`aikido_list_repos\` | List repositories |
+| \`aikido_ignore_issue\` | Mark issue as false positive |
+| \`aikido_add_note\` | Add note to issue |
-## Stappen
+## Steps
-1. **Analyseer** — Zoek de root cause in de code.
-2. **Fix** — Pas de code aan om de kwetsbaarheid op te lossen.
-3. **Verificeer** — Gebruik \`aikido_list_repos\` → \`aikido_scan_repo\` → \`aikido_issues_list\` om te controleren.
-4. **Documenteer** — \`aikido_add_note\` + schrijf \`aikido/SECURITY_FIX.md\`.
+1. **Analyze** — Find the root cause in the code.
+2. **Fix** — Modify the code to resolve the vulnerability.
+3. **Verify** — Use \`aikido_list_repos\` → \`aikido_scan_repo\` → \`aikido_issues_list\` to verify.
+4. **Document** — \`aikido_add_note\` + write \`aikido/SECURITY_FIX.md\`.
${issueSection}
-Belangrijk: geen git commits, alleen noodzakelijke wijzigingen.`;
+Important: no git commits, only necessary changes.`;
}
function generateIssueContext(issues, ws) {
@@ -89,10 +89,10 @@ function generateIssueContext(issues, ws) {
for (let n = 0; n < issues.length; n++) {
const i = issues[n];
const prefix = issues.length > 1 ? `### ${n + 1}. ` : '## ';
- content += `${prefix}${i.title || 'Onbekend'}\n`;
- content += `- **Severity**: ${i.severity || '?'} (score: ${i.severity_score ?? 'n.v.t.'})\n`;
- content += `- **Type**: ${i.type || 'n.v.t.'}\n`;
- content += `- **Package**: ${i.affected_package || 'n.v.t.'}\n\n`;
+ content += `${prefix}${i.title || 'Unknown'}\n`;
+ content += `- **Severity**: ${i.severity || '?'} (score: ${i.severity_score ?? 'n/a'})\n`;
+ content += `- **Type**: ${i.type || 'n/a'}\n`;
+ content += `- **Package**: ${i.affected_package || 'n/a'}\n\n`;
}
return content;
}
@@ -129,7 +129,7 @@ module.exports.register = async function register(ctx) {
return reply.code(400).send({ error: 'Verplichte velden: name, aikido_env_prefix, repo_path, workspace_id, language' });
}
const existing = getWorkspace(db, name);
- if (existing) return reply.code(409).send({ error: `Workspace "${name}" bestaat al` });
+ if (existing) return reply.code(409).send({ error: `Workspace "${name}" already exists` });
db.prepare('INSERT INTO aikido_workspaces (name, aikido_env_prefix, repo_path, workspace_id, language, code_repo_name) VALUES (?, ?, ?, ?, ?, ?)')
.run(name, aikido_env_prefix, repo_path.replace(/\\/g, '/'), workspace_id, language, code_repo_name || null);
return { ok: true };
@@ -141,7 +141,7 @@ module.exports.register = async function register(ctx) {
if (!ws) return reply.code(404).send({ error: `Workspace "${req.params.name}" niet gevonden` });
const { name, aikido_env_prefix, repo_path, workspace_id, language, code_repo_name } = req.body;
if (name && name !== req.params.name && getWorkspace(db, name)) {
- return reply.code(409).send({ error: `Workspace "${name}" bestaat al` });
+ return reply.code(409).send({ error: `Workspace "${name}" already exists` });
}
db.prepare(`UPDATE aikido_workspaces SET
name = COALESCE(?, name),
@@ -175,7 +175,7 @@ module.exports.register = async function register(ctx) {
const ws = getWorkspace(db, req.params.name);
if (!ws) return reply.code(404).send({ error: `Workspace "${req.params.name}" niet gevonden` });
const creds = resolveCreds(ws.aikido_env_prefix);
- if (!creds) return reply.code(401).send({ error: 'no_credentials', message: 'Geen Aikido credentials geconfigureerd' });
+ if (!creds) return reply.code(401).send({ error: 'no_credentials', message: 'No Aikido credentials configured' });
const page = parseInt(req.query?.page || '0', 10);
const perPage = parseInt(req.query?.per_page || '20', 10);
diff --git a/gateway/frontend/src/app/shared/pipes/rel-time.pipe.ts b/gateway/frontend/src/app/shared/pipes/rel-time.pipe.ts
index 77d9af0..37618fe 100644
--- a/gateway/frontend/src/app/shared/pipes/rel-time.pipe.ts
+++ b/gateway/frontend/src/app/shared/pipes/rel-time.pipe.ts
@@ -6,10 +6,10 @@ export class RelTimePipe implements PipeTransform {
const d = Math.floor(Date.now() / 1000) - unix;
if (d < -60) return `over ${Math.ceil(-d / 60)}m`;
if (d < 0) return `over ${-d}s`;
- if (d < 5) return 'zojuist';
+ if (d < 5) return 'just now';
if (d < 60) return `${d}s`;
if (d < 3600) return `${Math.floor(d / 60)}m`;
- if (d < 86400) return `${Math.floor(d / 3600)}u`;
+ if (d < 86400) return `${Math.floor(d / 3600)}h`;
return `${Math.floor(d / 86400)}d`;
}
}
diff --git a/gateway/src/dns-egress.ts b/gateway/src/dns-egress.ts
index 3e65ccf..d7d465d 100644
--- a/gateway/src/dns-egress.ts
+++ b/gateway/src/dns-egress.ts
@@ -132,8 +132,8 @@ async function doSanitize(): Promise
{
try {
fs.writeFileSync(RESOLV_CONF, rebuilt.join('\n'));
console.log(
- `[dns-egress] resolv.conf opgeschoond: egress=${working.join(',')} ` +
- `verwijderd=${broken.join(',')}`,
+ `[dns-egress] resolv.conf cleaned: egress=${working.join(',')} ` +
+ `removed=${broken.join(',')}`,
);
} catch (err: any) {
console.warn('[dns-egress] kon resolv.conf niet schrijven:', err.message);
diff --git a/gateway/src/docker.ts b/gateway/src/docker.ts
index 2eb394c..cc1884d 100644
--- a/gateway/src/docker.ts
+++ b/gateway/src/docker.ts
@@ -520,8 +520,8 @@ else
"$INST_PATH/jbr/bin/keytool" -importcert -noprompt -trustcacerts -alias huddle-ca \\
-file /usr/local/share/ca-certificates/huddle-ca.crt \\
-keystore "$INST_PATH/jbr/lib/security/cacerts" -storepass changeit >/dev/null 2>&1 \\
- && echo "[jb-config] huddle CA in JBR-keystore geimporteerd (na deploy)" \\
- || echo "[jb-config] WAARSCHUWING: JBR-keystore import faalde (na deploy)"
+ && echo "[jb-config] huddle CA imported in JBR-keystore (after deploy)" \\
+ || echo "[jb-config] WARNING: JBR-keystore import failed (after deploy)"
fi
break
fi
@@ -567,10 +567,10 @@ if [ -x "$JBR_KEYTOOL" ] && [ -f "$JBR_CACERTS" ]; then
"$JBR_KEYTOOL" -importcert -noprompt -trustcacerts -alias huddle-ca \\
-file /usr/local/share/ca-certificates/huddle-ca.crt \\
-keystore "$JBR_CACERTS" -storepass changeit >/dev/null 2>&1 \\
- && echo "[jb-config] huddle CA in JBR-keystore geimporteerd" \\
- || echo "[jb-config] WAARSCHUWING: JBR-keystore import faalde"
+ && echo "[jb-config] huddle CA imported in JBR-keystore" \\
+ || echo "[jb-config] WARNING: JBR-keystore import failed"
else
- echo "[jb-config] WAARSCHUWING: JBR keytool/cacerts niet gevonden op $IDEA_PATH/jbr"
+ echo "[jb-config] WARNING: JBR keytool/cacerts not found at $IDEA_PATH/jbr"
fi
fi
@@ -795,8 +795,8 @@ export async function createAndStartContainer(params: StartParams): Promise