From cc60e5a2944cf60758300a00eddf1e75965822db Mon Sep 17 00:00:00 2001 From: 0libote <79215282+0libote@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:10:11 +0000 Subject: [PATCH 1/8] feat: manage saved SSH and API credentials in setup --- .github/workflows/build.yml | 4 +- CONTRIBUTING.md | 10 ++ Dockerfile | 1 + README.md | 1 + docker/bin/t3-api | 10 ++ docker/bin/t3-ssh | 10 ++ docker/setup/app.js | 4 + docker/setup/client/credentials.js | 108 +++++++++++++ docker/setup/client/routes.js | 2 + docker/setup/console.css | 27 ++++ docker/setup/credentials.mjs | 128 +++++++++++++++ docker/setup/credentials/askpass.sh | 3 + docker/setup/credentials/cli.mjs | 47 ++++++ docker/setup/credentials/run.mjs | 83 ++++++++++ docker/setup/files/paths.mjs | 2 +- docker/setup/page.mjs | 1 + docker/setup/server.mjs | 32 +++- docs/media/server-credentials/desktop.png | Bin 0 -> 357240 bytes .../media/server-credentials/phone-editor.png | Bin 0 -> 55037 bytes docs/server-credentials.md | 95 +++++++++++ examples/skills/ssh-ha/SKILL.md | 19 +++ examples/skills/ssh/SKILL.md | 14 ++ scripts/console-preview.mjs | 1 + scripts/credentials-smoke.mjs | 39 +++++ scripts/credentials-ui-audit.mjs | 114 +++++++++++++ scripts/fixtures/console/credentials.json | 9 ++ scripts/lib/console-fixtures.cjs | 1 + scripts/smoke-test.sh | 7 + tests/credentials-api.test.mjs | 75 +++++++++ tests/credentials.test.mjs | 151 ++++++++++++++++++ tests/files-paths.test.mjs | 10 ++ tests/fixtures/credentials.mjs | 37 +++++ 32 files changed, 1042 insertions(+), 3 deletions(-) create mode 100755 docker/bin/t3-api create mode 100755 docker/bin/t3-ssh create mode 100644 docker/setup/client/credentials.js create mode 100644 docker/setup/credentials.mjs create mode 100755 docker/setup/credentials/askpass.sh create mode 100644 docker/setup/credentials/cli.mjs create mode 100644 docker/setup/credentials/run.mjs create mode 100644 docs/media/server-credentials/desktop.png create mode 100644 docs/media/server-credentials/phone-editor.png create mode 100644 docs/server-credentials.md create mode 100644 examples/skills/ssh-ha/SKILL.md create mode 100644 examples/skills/ssh/SKILL.md create mode 100644 scripts/credentials-smoke.mjs create mode 100644 scripts/credentials-ui-audit.mjs create mode 100644 scripts/fixtures/console/credentials.json create mode 100644 tests/credentials-api.test.mjs create mode 100644 tests/credentials.test.mjs create mode 100644 tests/fixtures/credentials.mjs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 852c77bc..7af03a8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,9 @@ jobs: bash tests/user-env.test.sh bash tests/run-t3.test.sh bash tests/persist-credentials.test.sh - for f in docker/setup/app.js docker/setup/client/*.js docker/setup/design/ui.js docker/router/*.mjs docker/runtime/*.mjs; do + sh -n docker/setup/credentials/askpass.sh + shellcheck -s sh -S warning docker/setup/credentials/askpass.sh + for f in docker/setup/app.js docker/setup/client/*.js docker/setup/credentials.mjs docker/setup/credentials/*.mjs docker/setup/design/ui.js docker/router/*.mjs docker/runtime/*.mjs; do node --check "$f" done node --test tests/*.test.mjs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4dded66..afec3675 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,6 +133,16 @@ and Chromium; set `CHROME_PATH` if needed. Screenshots go to `/tmp/t3-opencode-auth-ui` (`T3_AUTH_UI_OUTPUT` overrides it). These audits never read or change your real OpenCode credentials. +For Server credentials changes, run `node --test tests/credentials*.test.mjs` +and `node scripts/credentials-ui-audit.mjs`. The UI audit uses a real setup +server in a disposable home, synthetic credentials and intercepted connection +tests. It covers add/edit/delete, masked values, failed reads, concurrent edits +and repeated saves in light/dark, phone, tablet, desktop and an actual embedded +frame. Screenshots go to `/tmp/t3-credentials-ui` (`T3_CREDENTIALS_UI_OUTPUT` +overrides it). It never connects to a real SSH or Home Assistant server. +The image smoke suite also checks both installed helpers and a local API +round trip with a disposable saved token on each variant and architecture. + Releases are made from tags. Pushing `vX.Y.Z` builds each image for each architecture, tests each one against the exact digest that was pushed, runs the agent lifecycle test and measures the image size on amd64, and then combines diff --git a/Dockerfile b/Dockerfile index 959a3803..5c13fda0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -273,6 +273,7 @@ RUN "$T3_INFRA_NODE" /usr/local/share/t3-client/patch.mjs # shell and anyone typing it. Nothing in the image resolves it by name: the # entrypoint, the setup service and the helpers all use T3_INFRA_LAUNCHER. RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/lib/t3code/run-t3.sh /usr/local/bin/t3-* \ + /opt/t3-setup/credentials/askpass.sh \ && ln -sfn t3-admin /usr/local/bin/t3 # The agent names, for `docker exec claude` and friends: links to diff --git a/README.md b/README.md index a548cf9f..c1ebd004 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,7 @@ instead. Details: [Reaching the server from a phone](docs/remote-access.md). | [Upgrading T3 Code](docs/t3code-updates.md) | Stable and Nightly, auto-update, rollback | | [Toolchains](docs/toolchains.md) | Go, Rust and friends, any mise tool, per-project versions | | [Source control](docs/source-control.md) | gh, glab, fj, tea and az sign-in | +| [Server credentials](docs/server-credentials.md) | Saved SSH passwords and API tokens, used by name without putting values in chat | | [Publishing a port](docs/ports.md) | Public URLs for dev servers | | [Giving agents a browser](docs/agent-browser.md) | T3's server browser and the browser MCP servers | | [Context management](docs/context-management.md) | Global `AGENTS.md` and the shared skill library | diff --git a/docker/bin/t3-api b/docker/bin/t3-api new file mode 100755 index 00000000..2f2deeda --- /dev/null +++ b/docker/bin/t3-api @@ -0,0 +1,10 @@ +#!/bin/bash +set -euo pipefail +inherited_path="$PATH" +[ "$EUID" -ne 0 ] || PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +if [ "$EUID" -eq 0 ] && command -v gosu >/dev/null 2>&1 && id t3 >/dev/null 2>&1; then + exec env PATH="$inherited_path" "$(command -v gosu)" t3 "$0" "$@" +fi +# shellcheck source=/dev/null +[ ! -r /etc/profile.d/t3-user-env.sh ] || . /etc/profile.d/t3-user-env.sh +exec "${T3_INFRA_NODE:-/usr/local/bin/node}" "${T3_CREDENTIAL_CLI:-/opt/t3-setup/credentials/cli.mjs}" api "$@" diff --git a/docker/bin/t3-ssh b/docker/bin/t3-ssh new file mode 100755 index 00000000..296ca7c5 --- /dev/null +++ b/docker/bin/t3-ssh @@ -0,0 +1,10 @@ +#!/bin/bash +set -euo pipefail +inherited_path="$PATH" +[ "$EUID" -ne 0 ] || PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +if [ "$EUID" -eq 0 ] && command -v gosu >/dev/null 2>&1 && id t3 >/dev/null 2>&1; then + exec env PATH="$inherited_path" "$(command -v gosu)" t3 "$0" "$@" +fi +# shellcheck source=/dev/null +[ ! -r /etc/profile.d/t3-user-env.sh ] || . /etc/profile.d/t3-user-env.sh +exec "${T3_INFRA_NODE:-/usr/local/bin/node}" "${T3_CREDENTIAL_CLI:-/opt/t3-setup/credentials/cli.mjs}" ssh "$@" diff --git a/docker/setup/app.js b/docker/setup/app.js index 3d100e2c..76be4c58 100644 --- a/docker/setup/app.js +++ b/docker/setup/app.js @@ -152,6 +152,7 @@ const skillsUI = T3SkillsUI.create({ api, getStatus: () => state.status, render: () => render(), readMarkdown: (file) => readMarkdownFile(file, 64 * 1024), downloadMarkdown: (...args) => downloadMarkdown(...args) }); const mcpUI = T3McpUI.create({ api, getStatus: () => state.status, render: () => render() }); + const credentialsUI = T3CredentialsUI.create({ api, render: () => render() }); const filesUI = T3FilesUI.create({ api, base: BASE, getStatus: () => state.status, getRoute: () => state.route, render: () => render(), go: route => go(route) }); /** Whether this browser came in on its T3 Code session rather than the key, so Lock would end nothing. */ @@ -230,6 +231,7 @@ checkHere(); if (state.route === 'instructions' && state.contextTab === 'skills') skillsUI.activate(); if (state.route === 'mcp') mcpUI.activate(); + if (state.route === 'credentials') credentialsUI.activate(); if (state.route === 'files') filesUI.activate(); if (state.route === 'instructions' && state.contextTab === 'instructions') void loadInstructionsPreview(); } else if (!locked) { @@ -1806,6 +1808,7 @@ files: () => html`${filesUI.phoneHead()}${pageHead('files')}${filesUI.content()}`, overview: overviewPage, access: accessPage, agents: agentsPage, instructions: instructionsPage, mcp: () => html`${mcpUI.phoneHead()}${pageHead('mcp', { sub: 'Servers your agents can start or connect to. Define one once, then add it to the agents you choose.' })}${mcpUI.content()}`, + credentials: () => html`${pageHead('credentials')}${credentialsUI.content()}`, toolchains: toolchainsPage, sourcecontrol: sourceControlPage, ports: portsPage, updates: updatesPage, storage: storagePage, server: serverPage, more: morePage, }; @@ -1904,6 +1907,7 @@ if (route === 'instructions' && state.contextTab === 'skills' && state.status) skillsUI.activate(true); if (route === 'instructions' && state.contextTab === 'instructions' && state.status) void loadInstructionsPreview(true); if (route === 'mcp' && state.status) mcpUI.activate(true); + if (route === 'credentials' && state.status) credentialsUI.activate(true); if (route === 'files' && state.status) filesUI.activate(); }; const navigateFromHash = async focus => { diff --git a/docker/setup/client/credentials.js b/docker/setup/client/credentials.js new file mode 100644 index 00000000..1c95477e --- /dev/null +++ b/docker/setup/client/credentials.js @@ -0,0 +1,108 @@ +// Saved secrets are write-only. Only the newly typed replacement lives in +// the dialog's input; it is never rendered, cached or copied into instructions. +const T3CredentialsUI = (() => { + 'use strict'; + const { html, raw, icon } = Kit; + const disabled = value => value ? raw(' disabled') : ''; + const create = ({ api, render }) => { + let data = null, loading = false, error = null, started = false, epoch = 0, editor = null, notice = null; + const busy = new Set(), results = new Map(); + const notify = (message, options) => { notice?.close(); notice = Kit.toast(message, options); }; + const paint = () => { + render(); + const mount = document.getElementById('credential-list'); + if (mount) Kit.patch(mount, body()); + }; + const load = async () => { + const version = ++epoch; + started = true; loading = true; error = null; paint(); + const response = await api('/credentials'); + if (version !== epoch) return; + if (response.ok && Array.isArray(response.data?.profiles)) data = response.data; + else error = response.error || 'Could not load saved connections.'; + loading = false; paint(); + }; + const command = profile => profile.type === 'ssh' ? 't3-ssh ' + profile.id + ' -- uptime' : 't3-api ' + profile.id + ' GET ""'; + const body = () => html` +
${data ? T3Model.plural(data.profiles.length, 'saved connection') : 'Saved connections'}
+ ${error ? html`` : ''} + ${!data ? html`
${loading ? 'Loading connections…' : 'Connections unavailable'}
` : data.profiles.length ? html`
${data.profiles.map(profile => html` +
+ +
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}${command(profile)}${profile.type === 'ssh' ? 'Password saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
+
+
`)}
` : html`
Save a connection once

Keep SSH passwords and API tokens here. Your skills use the connection ID, so credentials stay out of instructions and chat.

`} +

${icon('lock-keyhole', 'tc-icon--sm')}Saved on this server. Values are hidden from the page and filtered from helper output. Any agent with shell access can use these connections.

`; + + const openEditor = profile => { + if (editor || !data || error || loading) return; + notice?.close(); notice = null; + const view = { original: profile, revision: data.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '' }, busy: false, error: null }; + editor = view; + const field = (key, label, options = {}) => html`
${options.hint ? html`

${options.hint}

` : ''}
`; + const markup = () => html`
+

${profile ? 'Edit connection' : 'Add connection'}

${profile ? 'Leave the secret blank to keep its saved value.' : 'Save the login here, then use its connection ID in your skills.'}

+
+ ${field('label', 'Name', { max: 120 })} + ${field('id', 'Connection ID', { locked: Boolean(profile), max: 64, hint: 'Lowercase letters, numbers and hyphens. Used in helper commands.' })} +
+ ${view.draft.type === 'ssh' ? html`${field('host', 'Host', { max: 253 })}
${field('username', 'Username', { max: 64 })}${field('port', 'Port', { type: 'number' })}
` : field('baseUrl', 'API base URL', { max: 2048, hint: 'Include the API path, for example http://homeassistant.local/api/.' })} +

${profile ? 'A value is saved. Enter a replacement only if you want to change it.' : 'This value will not appear in the saved connection details.'}

+
${view.error ? html`` : ''} +
`; + const close = () => { if (!view.busy) view.layer.close(); }; + view.layer = Kit.open({ kind: 'center', backdrop: 'ignore', focus: '#credential-label', + panel: { tag: 'form', class: 'tc-dialog tc-credential-editor', role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'credential-title', autocomplete: 'off' }, + render: markup, onEscape: close, onClose: () => { const input = view.layer.panel.querySelector('#credential-secret'); if (input) input.value = ''; if (editor === view) editor = null; }, + }); + view.layer.panel.addEventListener('input', event => { + const key = event.target.dataset.credentialField; + if (key && !view.busy) view.draft[key] = event.target.value; + }); + view.layer.panel.addEventListener('change', event => { + if (event.target.dataset.credentialField === 'type' && !view.busy) { view.draft.type = event.target.value; view.layer.render(); } + }); + view.layer.panel.addEventListener('click', event => { if (event.target.closest('[data-credential-cancel]')) close(); }); + view.layer.panel.addEventListener('submit', async event => { + event.preventDefault(); + if (view.busy || editor !== view) return; + const secretInput = view.layer.panel.querySelector('#credential-secret'); + const payload = { ...view.draft, port: Number(view.draft.port), secret: secretInput.value || undefined }; + view.busy = true; view.error = null; view.layer.render(); + const response = await api(profile ? '/credentials/save' : '/credentials/create', { body: { profile: payload, revision: view.revision } }); + delete payload.secret; + if (response.ok) { + secretInput.value = ''; results.delete(view.draft.id); + if (editor === view) { view.busy = false; view.layer.close('saved'); } + notify('Connection saved'); await load(); + } else if (editor === view) { + view.busy = false; view.error = response.error; view.layer.render(); + view.layer.panel.querySelector('#credential-error')?.focus(); + } + }); + }; + document.addEventListener('click', async event => { + const button = event.target.closest('[data-credential-action]'); + if (!button || button.disabled) return; + const action = button.dataset.credentialAction, profile = data?.profiles.find(row => row.id === button.dataset.id); + if (action === 'reload') { void load(); return; } + if (action === 'add') { openEditor(); return; } + if (!profile || busy.has(profile.id) || error) return; + if (action === 'edit') { openEditor(profile); return; } + const revision = data.revision; + if (action === 'remove') { + const yes = await Kit.confirm({ title: 'Delete ' + profile.label + '?', body: 'Removes the saved login. Skills using ' + profile.id + ' will need another connection.', confirm: 'Delete connection', tone: 'danger' }); + if (!yes || busy.has(profile.id)) return; + } + busy.add(profile.id); results.delete(profile.id); paint(); + const response = await api('/credentials/' + action, { body: { id: profile.id, revision } }); + busy.delete(profile.id); + if (action === 'test') results.set(profile.id, { ok: response.ok, message: response.ok ? 'Connection succeeded' : response.error }); + else if (response.ok) notify('Connection deleted'); + else notify('Could not delete connection', { tone: 'danger', detail: response.error }); + await load(); + }); + return { content: () => html`
${body()}
`, activate: (force = false) => { if (!loading && (force || !started)) void load(); } }; + }; + return { create }; +})(); diff --git a/docker/setup/client/routes.js b/docker/setup/client/routes.js index 3f5f26cf..be03cf69 100644 --- a/docker/setup/client/routes.js +++ b/docker/setup/client/routes.js @@ -27,6 +27,8 @@ const T3Routes = (() => { summary: 'Servers your agents can start or connect to.', doc: 'mcp-servers.md' }, { route: 'files', title: 'Files', icon: 'folder', key: 'f', group: 'tools', summary: 'Your projects, your home folder and what fills the disk.', doc: 'files.md' }, + { route: 'credentials', title: 'Server credentials', icon: 'key-round', key: 'c', group: 'tools', + summary: 'SSH passwords and API tokens your agents can use by name.', doc: 'server-credentials.md' }, { route: 'toolchains', title: 'Toolchains', icon: 'wrench', key: 't', group: 'tools', summary: 'Languages and tools on every agent’s path, at exact versions.', doc: 'toolchains.md' }, { route: 'sourcecontrol', title: 'Source control', icon: 'git-pull-request', key: 's', group: 'tools', diff --git a/docker/setup/console.css b/docker/setup/console.css index e515d534..d8f94fb2 100644 --- a/docker/setup/console.css +++ b/docker/setup/console.css @@ -3085,3 +3085,30 @@ body[data-console-route="files"]:has(.tc-layer) .tc-toaster { visibility: hidden .tc-files-zip .tc-opt small { overflow-wrap: anywhere; } .tc-files-archive-contents span:not(.tc-small) { max-width: 100%; min-width: 0; } .tc-files-archive-contents code { min-width: 0; overflow-wrap: anywhere; } +/* Server logins use the console's existing forms and controls. Long addresses + wrap independently of the actions, including in the embedded phone view. */ +.tc-credential-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; } +.tc-credential-row { display: flex; align-items: flex-start; gap: 12px; padding: 20px; } +.tc-credential-row + .tc-credential-row { border-top: 1px solid var(--border); } +.tc-credential-main { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: 6px; } +.tc-credential-main strong { font-size: 14px; overflow-wrap: anywhere; } +.tc-credential-address, .tc-credential-command { overflow-wrap: anywhere; } +.tc-credential-command { font-size: 12px; color: var(--fg-muted); } +.tc-credential-actions { display: flex; gap: 8px; flex-wrap: wrap; } +.tc-credential-note { display: flex; align-items: flex-start; gap: 8px; margin-top: 16px; } +.tc-credential-note svg { flex: 0 0 auto; margin-top: 2px; } +.tc-layer--center > .tc-credential-editor { display: flex; flex-direction: column; width: min(520px, calc(100vw - 24px)); overflow: hidden; } +.tc-credential-editor > .tc-dialog-body { min-height: 0; overflow-y: auto; } +.tc-credential-editor > .tc-dialog-foot { flex: none; } +.tc-credential-editor .tc-form { margin-top: 12px; } +.tc-credential-fields { display: grid; grid-template-columns: minmax(0, 1fr) 110px; gap: 12px; } +@media (max-width: 600px) { + .tc-credential-row { padding: 16px; flex-wrap: wrap; } + .tc-credential-main { flex-basis: calc(100% - 56px); } + .tc-credential-actions { margin-left: 44px; } + .tc-credential-toolbar > .tc-small { flex-basis: 100%; } +} +.tc-root[data-density="touch"] :is(.tc-credential-actions, .tc-credential-toolbar, .tc-credential-editor .tc-dialog-foot) .tc-btn { min-height: var(--touch); min-width: var(--touch); } +@media (max-width: 1023.98px) { + .tc-layer--center > .tc-credential-editor { width: 100%; max-width: none; } +} diff --git a/docker/setup/credentials.mjs b/docker/setup/credentials.mjs new file mode 100644 index 00000000..8a784c4e --- /dev/null +++ b/docker/setup/credentials.mjs @@ -0,0 +1,128 @@ +// Public reads return connection details only. Helpers read secrets directly, +// so saved passwords and tokens never need to pass through an agent prompt. +import * as fs from 'node:fs/promises'; +import { constants } from 'node:fs'; +import path from 'node:path'; +import { createHash, randomUUID } from 'node:crypto'; + +export class CredentialError extends Error { + constructor(message, status = 400) { super(message); this.status = status; } +} +const fail = (message, status) => { throw new CredentialError(message, status); }; +const MAX_BYTES = 512 * 1024; +const object = value => value && typeof value === 'object' && !Array.isArray(value); +const text = (value, max) => typeof value === 'string' && value.isWellFormed() && value.length > 0 && value.length <= max && !/[\x00-\x1f\x7f]/.test(value); +export const credentialDirectory = (env = process.env) => path.join(env.T3CODE_HOME || path.join(env.HOME || '/home/t3', '.t3'), 'server-credentials'); + +function normalize(input, previous) { + if (!object(input)) fail('Enter connection details.'); + if (!text(input.id, 64) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.id)) fail('Use up to 64 lowercase letters, numbers and single hyphens for the connection ID.'); + if (!text(input.label, 120) || !input.label.trim()) fail('Enter a connection name of up to 120 characters.'); + if (!['ssh', 'api'].includes(input.type)) fail('Choose SSH password or API token.'); + if (previous && previous.type !== input.type) fail('Create a new connection to change its type.'); + const secret = input.secret === undefined || input.secret === '' ? previous?.secret : input.secret; + if (!text(secret, 8192)) fail('Enter a password or token of up to 8192 characters, without line breaks.'); + const profile = { id: input.id, label: input.label.trim(), type: input.type, secret }; + if (input.type === 'ssh') { + if (!text(input.host, 253) || !/^[a-zA-Z0-9][a-zA-Z0-9.:-]*$/.test(input.host)) fail('Enter a hostname or IP address, without a username or port.'); + if (!text(input.username, 64) || !/^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(input.username)) fail('Enter a valid SSH username.'); + if (!Number.isInteger(input.port) || input.port < 1 || input.port > 65535) fail('Enter an SSH port from 1 to 65535.'); + Object.assign(profile, { host: input.host, username: input.username, port: input.port }); + } else { + let url; + try { url = new URL(input.baseUrl); } catch { fail('Enter a complete http:// or https:// API address.'); } + if (!text(input.baseUrl, 2048) || !['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) fail('Use an HTTP or HTTPS API address without credentials, a query or a fragment.'); + if (!url.pathname.endsWith('/')) url.pathname += '/'; + profile.baseUrl = url.href; + } + return profile; +} + +const publicProfile = ({ secret, ...profile }) => ({ ...profile, hasSecret: true }); +const revisionOf = text => createHash('sha256').update(text).digest('hex'); +const EMPTY = JSON.stringify({ version: 1, profiles: [] }); +export const credentialFailure = error => error instanceof CredentialError + ? { status: error.status, body: { ok: false, error: error.message } } + : { status: 500, body: { ok: false, error: 'Could not access saved credentials. Check the state volume and its permissions.' } }; + +export function createCredentialStore({ directory = credentialDirectory() } = {}) { + const file = path.join(directory, 'credentials.json'); + let queue = Promise.resolve(); + const serial = action => { + const result = queue.then(action); + queue = result.catch(() => {}); + return result; + }; + const secureDirectory = async () => { + await fs.mkdir(directory, { recursive: true, mode: 0o700 }); + const stat = await fs.lstat(directory); + if (!stat.isDirectory() || stat.uid !== process.getuid()) fail('The credential directory must belong to the container user and must not be a symbolic link.', 500); + await fs.chmod(directory, 0o700); + }; + const read = async () => { + await secureDirectory(); + let handle, raw = EMPTY; + try { + handle = await fs.open(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); + const stat = await handle.stat(); + if (!stat.isFile() || stat.nlink !== 1 || stat.uid !== process.getuid() || stat.size > MAX_BYTES) fail('The credential file is unsafe or exceeds its size limit. Repair it before continuing.', 500); + await handle.chmod(0o600); + raw = await handle.readFile('utf8'); + } catch (error) { + if (error.code !== 'ENOENT') throw error; + } finally { await handle?.close(); } + let data; + try { + data = JSON.parse(raw); + if (data.version !== 1 || !Array.isArray(data.profiles) || data.profiles.length > 64) throw new Error(); + data.profiles = data.profiles.map(profile => normalize(profile)); + if (new Set(data.profiles.map(profile => profile.id)).size !== data.profiles.length) throw new Error(); + } catch { fail('Saved credentials could not be read. Restore the credential file before making changes.', 500); } + return { profiles: data.profiles, revision: revisionOf(raw) }; + }; + const write = async profiles => { + const raw = JSON.stringify({ version: 1, profiles }, null, 2) + '\n'; + if (Buffer.byteLength(raw) > MAX_BYTES) fail('Saved credentials exceed the 512 KiB limit.'); + const temporary = path.join(directory, '.' + randomUUID() + '.tmp'); + try { + const handle = await fs.open(temporary, 'wx', 0o600); + try { await handle.writeFile(raw); await handle.sync(); } finally { await handle.close(); } + await fs.rename(temporary, file); + } finally { await fs.rm(temporary, { force: true }); } + return revisionOf(raw); + }; + const checkRevision = (expected, actual) => { + if (expected !== actual) fail('Connections changed in another window. Close this editor, reload the list and reopen the connection before saving again.', 409); + }; + return { + async list() { + const data = await read(); + return { profiles: data.profiles.map(publicProfile), revision: data.revision }; + }, + save: ({ profile, revision, create = false }) => serial(async () => { + const data = await read(); + checkRevision(revision, data.revision); + const index = data.profiles.findIndex(row => row.id === profile?.id); + if (create && index >= 0) fail('This connection ID is already in use. Choose another ID.', 409); + if (!create && index < 0) fail('This connection no longer exists. Reload the list.', 409); + const saved = normalize(profile, data.profiles[index]); + if (index < 0) { + if (data.profiles.length >= 64) fail('Save at most 64 connections.'); + data.profiles.push(saved); + } else data.profiles[index] = saved; + return { profile: publicProfile(saved), revision: await write(data.profiles) }; + }), + remove: ({ id, revision }) => serial(async () => { + const data = await read(); + checkRevision(revision, data.revision); + if (!data.profiles.some(row => row.id === id)) fail('This connection no longer exists.', 404); + return { revision: await write(data.profiles.filter(row => row.id !== id)) }; + }), + async forUse(id) { + const data = await read(); + const profile = data.profiles.find(row => row.id === id); + if (!profile) fail('Saved connection not found. Add it in Setup → Server credentials.', 404); + return profile; + }, + }; +} diff --git a/docker/setup/credentials/askpass.sh b/docker/setup/credentials/askpass.sh new file mode 100755 index 00000000..047633e9 --- /dev/null +++ b/docker/setup/credentials/askpass.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Only ssh reads this output; it never passes through the helper's stdout. +printf '%s\n' "$T3_CREDENTIAL_PASSWORD" diff --git a/docker/setup/credentials/cli.mjs b/docker/setup/credentials/cli.mjs new file mode 100644 index 00000000..29d7ca61 --- /dev/null +++ b/docker/setup/credentials/cli.mjs @@ -0,0 +1,47 @@ +import { createCredentialStore, credentialFailure, CredentialError } from '../credentials.mjs'; +import { sshRequest, apiRequest } from './run.mjs'; + +const USAGE = `Use saved credentials without putting their values in commands: + t3-ssh CONNECTION [--] COMMAND [ARGUMENT...] + t3-api CONNECTION METHOD RELATIVE_PATH [--stdin] + +Manage connections in Setup → Server credentials. +For JSON request bodies, use --stdin and pipe the body into t3-api. +Examples: + t3-ssh homeserver -- uptime + t3-api homeassistant GET states/light.kitchen + printf '%s' '{"entity_id":"light.kitchen"}' | t3-api homeassistant POST services/light/turn_on --stdin +`; + +async function main() { + const [kind, ...args] = process.argv.slice(2); + if (args.length === 0 || args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; } + const id = args.shift(), store = createCredentialStore(); + if (!['ssh', 'api'].includes(kind)) throw new CredentialError('Use t3-ssh or t3-api.'); + if (kind === 'ssh') { + if (args[0] === '--') args.shift(); + if (!args.length) throw new CredentialError('Supply a remote command after the connection ID.'); + process.exitCode = await sshRequest(await store.forUse(id), args); + } else { + const [method, relative, option, ...extra] = args; + if (!method || relative === undefined || extra.length || option !== undefined && option !== '--stdin') throw new CredentialError('Use t3-api CONNECTION METHOD RELATIVE_PATH [--stdin].'); + let body; + if (option === '--stdin') { + if (['GET', 'HEAD'].includes(method)) throw new CredentialError('GET and HEAD requests cannot have a body.'); + const chunks = []; let length = 0; + for await (const chunk of process.stdin) { + length += chunk.length; + if (length > 1024 * 1024) throw new CredentialError('The JSON request body exceeds 1 MiB.'); + chunks.push(chunk); + } + body = Buffer.concat(chunks).toString('utf8'); + try { JSON.parse(body); } catch { throw new CredentialError('Supply a valid JSON request body on stdin.'); } + } + process.exitCode = await apiRequest(await store.forUse(id), method, relative, { body }); + } +} + +main().catch(error => { + process.stderr.write(credentialFailure(error).body.error + '\n'); + process.exitCode = 1; +}); diff --git a/docker/setup/credentials/run.mjs b/docker/setup/credentials/run.mjs new file mode 100644 index 00000000..af1ce421 --- /dev/null +++ b/docker/setup/credentials/run.mjs @@ -0,0 +1,83 @@ +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { Readable } from 'node:stream'; +import { CredentialError } from '../credentials.mjs'; + +// Keep matches that straddle output chunks private too. Encoded JSON/API +// echoes and URL-encoded diagnostics are scrubbed alongside the literal value. +export function outputFilter(secret, write) { + const values = [...new Set([secret, JSON.stringify(secret).slice(1, -1), encodeURIComponent(secret), Buffer.from(secret).toString('base64')])].filter(Boolean).sort((a, b) => b.length - a.length); + const pattern = new RegExp(values.map(value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g'); + const keep = Math.max(...values.map(value => value.length)) - 1; + let pending = ''; + const flush = final => { + let cut = final ? pending.length : Math.max(0, pending.length - keep); + for (const match of pending.matchAll(pattern)) { + if (match.index < cut && match.index + match[0].length > cut) cut = match.index + match[0].length; + } + if (cut) { write(pending.slice(0, cut).replace(pattern, '[redacted]')); pending = pending.slice(cut); } + }; + return { write(chunk) { pending += chunk; flush(false); }, end() { flush(true); } }; +} + +async function pump(stream, write, secret) { + stream.setEncoding('utf8'); + const filter = outputFilter(secret, write); + try { for await (const chunk of stream) filter.write(chunk); } + finally { filter.end(); } +} + +export async function sshRequest(profile, command, { stdout = process.stdout, stderr = process.stderr, stdin = 'inherit', probe = false, signal, spawnProcess = spawn } = {}) { + if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH connection.'); + const args = ['-T', '-p', String(profile.port), '-l', profile.username, + '-o', 'ConnectTimeout=10', '-o', 'ConnectionAttempts=1', '-o', 'NumberOfPasswordPrompts=1', + '-o', 'BatchMode=no', '-o', 'ControlPath=none', + '-o', 'StrictHostKeyChecking=accept-new', '-o', 'PreferredAuthentications=password,keyboard-interactive', + '-o', 'PubkeyAuthentication=no', '--', profile.host, ...command]; + const child = spawnProcess('/usr/bin/ssh', args, { + env: { ...process.env, SSH_ASKPASS: fileURLToPath(new URL('./askpass.sh', import.meta.url)), + SSH_ASKPASS_REQUIRE: 'force', DISPLAY: process.env.DISPLAY || 't3-credentials', T3_CREDENTIAL_PASSWORD: profile.secret }, + stdio: [stdin, 'pipe', 'pipe'], signal, + }); + const done = new Promise((resolve, reject) => { + child.once('error', () => reject(new CredentialError('SSH could not start or was interrupted.', 502))); + child.once('close', code => resolve(code ?? 1)); + }); + const discard = () => {}; + const [, , code] = await Promise.all([ + pump(child.stdout, probe ? discard : value => stdout.write(value), profile.secret), + pump(child.stderr, probe ? discard : value => stderr.write(value), profile.secret), done, + ]); + if (probe && code !== 0) throw new CredentialError('SSH connection failed. Check the address, login details and saved host key.', 502); + return code; +} + +export function apiTarget(profile, relative) { + if (profile.type !== 'api') throw new CredentialError('Choose an API token connection.'); + if (typeof relative !== 'string' || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) throw new CredentialError('Use a path relative to the saved API address, such as states/light.kitchen.'); + const base = new URL(profile.baseUrl), target = new URL(relative || '.', base); + if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.username || target.password || target.hash) throw new CredentialError('The request must stay inside the saved API address.'); + return target; +} + +export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, probe = false, signal = AbortSignal.timeout(30000) } = {}) { + if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new CredentialError('Use GET, HEAD, POST, PUT, PATCH or DELETE.'); + const target = apiTarget(profile, relative); + try { + const response = await fetch(target, { method, redirect: 'error', signal, + headers: { authorization: 'Bearer ' + profile.secret, accept: 'application/json', ...(body === undefined ? {} : { 'content-type': 'application/json' }) }, body }); + if (probe) { + await response.body?.cancel(); + if (!response.ok) throw new CredentialError('The API did not accept the request (HTTP ' + response.status + '). Check the address and token.', 502); + } else if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); + return response.ok ? 0 : 1; + } catch (error) { + if (error instanceof CredentialError) throw error; + throw new CredentialError('API request failed. Check the address, certificate and network; redirects are not followed.', 502); + } +} + +export const testCredential = (profile, { signal = AbortSignal.timeout(15000) } = {}) => { + return profile.type === 'ssh' ? sshRequest(profile, ['true'], { probe: true, stdin: 'ignore', signal }) + : apiRequest(profile, 'GET', '', { probe: true, signal }); +}; diff --git a/docker/setup/files/paths.mjs b/docker/setup/files/paths.mjs index d0bddcb6..d56f6a06 100644 --- a/docker/setup/files/paths.mjs +++ b/docker/setup/files/paths.mjs @@ -72,7 +72,7 @@ export function createPathPolicy({ home = os.homedir(), workspace = '/workspace' ['Cursor', path.join(home, '.cursor'), 'cli-config.json'], ['Muse Code', path.join(configHome, 'muse'), 'auth.json'], ].map(([name, root, file]) => ({ name, root, file: path.join(root, file) })); - const keyRoots = guarded.keys.paths.map(value => path.join(home, value.slice(2))); + const keyRoots = [...guarded.keys.paths.map(value => path.join(home, value.slice(2))), path.join(t3Root, 'server-credentials')]; const location = async value => { try { return await io.realpath(value); } catch { try { return await canonicalEntry(value, io); } catch { return path.resolve(value); } } diff --git a/docker/setup/page.mjs b/docker/setup/page.mjs index 55304b7a..f8aedac7 100644 --- a/docker/setup/page.mjs +++ b/docker/setup/page.mjs @@ -43,6 +43,7 @@ export const CONSOLE_SCRIPTS = [ "client/mcp-inspector.js", "client/mcp-editor.js", "client/mcp.js", + "client/credentials.js", "client/files-model.js", "client/files-editor.js", "client/files-dialogs.js", diff --git a/docker/setup/server.mjs b/docker/setup/server.mjs index aa1c844d..b5b71187 100644 --- a/docker/setup/server.mjs +++ b/docker/setup/server.mjs @@ -38,6 +38,8 @@ import { createSkillsService } from "./skills.mjs"; import { createMcpService } from "./mcp.mjs"; import { clientAddress } from "./client-address.mjs"; import { newKey, readKeyFile, writeKeyFile } from "./setup-key.mjs"; +import { createCredentialStore, credentialFailure, CredentialError } from "./credentials.mjs"; +import { testCredential } from "./credentials/run.mjs"; import { connectState, jsonFrom, parseLinkOutput } from "./connect.mjs"; import { checkReaches, clearSaved, parsePublicUrl, platformUrl, readSaved, resolvePublicUrl, writeSaved, @@ -67,6 +69,9 @@ const SINGLE_PORT = Number(process.env.T3_SINGLE_PORT) || null; const SINGLE_PREFIX = BASE_PATH ? (BASE_PATH.startsWith("/") ? BASE_PATH : `/${BASE_PATH}`) : "/__setup"; // Where T3 Code keeps its state; the volume a user mounts is the home around it. const STATE_DIR = process.env.T3CODE_HOME || `${process.env.HOME || "/home/t3"}/.t3`; +const credentials = createCredentialStore(); +const credentialShutdown = new AbortController(); +let credentialTests = 0; const VOLUME = process.env.HOME || STATE_DIR.replace(/\/\.t3\/?$/, "") || STATE_DIR; const WORKSPACE = process.env.T3_WORKSPACE || "/workspace"; // The setup key and where it came from (setup-key.mjs): "env" for @@ -2163,7 +2168,7 @@ const cancelLifecycle = (target, rawId) => { return { http: 404, body: { ok: false, code: "not-running", error: "Nothing is running or waiting for that row." } }; }; -const ROUTES = [...FILES_ROUTES, "/login", "/logout", "/hello", "/status", "/pair", "/revoke", "/devices/rename", "/ports", +const ROUTES = [...FILES_ROUTES, "/credentials", "/credentials/create", "/credentials/save", "/credentials/remove", "/credentials/test", "/login", "/logout", "/hello", "/status", "/pair", "/revoke", "/devices/rename", "/ports", "/storage/versions/prune", "/storage/versions", "/storage/refresh", "/storage/clean/preview", "/storage/clean", "/storage/policy", "/storage", "/public-url/clear", "/public-url", "/setup-key/reveal", "/setup-key/replace", "/connect/unlink", "/t3/restart", "/t3/updates/check", "/t3/update", "/ports/expose", "/ports/unexpose", @@ -2489,6 +2494,30 @@ const server = createServer(async (req, res) => { // where locking would end something. if (route === "/status") return sendJson(res, 200, { ...(await status()), viewer: { via: viewer.via } }); + if (route === '/credentials' || route.startsWith('/credentials/')) { + if (req.method !== (route === '/credentials' ? 'GET' : 'POST')) return sendJson(res, 405, { ok: false, error: 'Use the supported method for this credential action.' }); + try { + if (route === '/credentials') return sendJson(res, 200, { ok: true, ...await credentials.list() }); + let input; + try { input = JSON.parse(await readBody(req)); } + catch (error) { return sendJson(res, error.message === 'body too large' ? 413 : 400, { ok: false, error: 'Send connection details as a JSON object of at most 64 KiB.' }); } + if (!input || typeof input !== 'object' || Array.isArray(input)) throw new CredentialError('Send connection details as a JSON object.'); + if (route === '/credentials/create' || route === '/credentials/save') return sendJson(res, 200, { ok: true, ...await credentials.save({ ...input, create: route === '/credentials/create' }) }); + if (route === '/credentials/remove') return sendJson(res, 200, { ok: true, ...await credentials.remove(input) }); + if (route === '/credentials/test') { + if (credentialTests >= 3) throw new CredentialError('Other connections are being tested. Try again in a moment.', 409); + credentialTests++; + try { + const snapshot = await credentials.list(); + if (snapshot.revision !== input.revision) throw new CredentialError('Connections changed. Reload the list before testing again.', 409); + await testCredential(await credentials.forUse(input.id), { signal: AbortSignal.any([AbortSignal.timeout(15000), credentialShutdown.signal]) }); + return sendJson(res, 200, { ok: true, message: 'Connection succeeded.' }); + } finally { credentialTests--; } + } + return sendJson(res, 404, { ok: false, error: 'Credential action not found.' }); + } catch (error) { const failure = credentialFailure(error); return sendJson(res, failure.status, failure.body); } + } + if (route.startsWith("/files/")) { if (req.method !== (FILES_POST_ROUTES.includes(route) ? "POST" : "GET")) return sendJson(res, 405, { ok: false, code: "invalid", error: "Use the supported method for this Files action." }); let payloadLease = false; @@ -3057,6 +3086,7 @@ const server = createServer(async (req, res) => { // tracking them - a sign-in nobody can finish, a URL nobody can stop - so // they go when the service does, however it goes. const stopChildren = () => { + credentialShutdown.abort(); filesInstance?.stop(); for (const session of sessions.values()) { if (!TERMINAL_STATES.has(session.state)) { diff --git a/docs/media/server-credentials/desktop.png b/docs/media/server-credentials/desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..eba84abbf454677cfe56c4dd92f7f88746bbd20e GIT binary patch literal 357240 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 z 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 G0sjZjlgqaN literal 0 HcmV?d00001 diff --git a/docs/media/server-credentials/phone-editor.png b/docs/media/server-credentials/phone-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..3baa724e8d2462105d662c3230650fb1542d9006 GIT binary patch literal 55037 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 yOk!YAW9-I7 diff --git a/docs/server-credentials.md b/docs/server-credentials.md index d8187e34..ae8900da 100644 --- a/docs/server-credentials.md +++ b/docs/server-credentials.md @@ -5,8 +5,6 @@ of skill files and agent prompts. Save a connection, then give the agent its connection ID. The page supports adding, editing, testing and deleting connections on desktop and phone, including inside T3 Code's Settings → Setup dialog. -![Server credentials in the setup console, using example addresses.](media/server-credentials/desktop.png) - Choose **Add connection**, enter a name and a stable ID such as `homeserver`, then choose a type: From b3f94473685d2d887e6e6ad7d57160d589ebc18f Mon Sep 17 00:00:00 2001 From: 0libote <79215282+0libote@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:37:29 +0000 Subject: [PATCH 3/8] feat: copy saved connection commands for skills --- docker/setup/client/credentials.js | 3 ++- docker/setup/console.css | 5 ++++- docs/server-credentials.md | 4 ++++ scripts/credentials-ui-audit.mjs | 11 +++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docker/setup/client/credentials.js b/docker/setup/client/credentials.js index 1c95477e..fd1638eb 100644 --- a/docker/setup/client/credentials.js +++ b/docker/setup/client/credentials.js @@ -29,7 +29,7 @@ const T3CredentialsUI = (() => { ${!data ? html`

` : data.profiles.length ? html`
${data.profiles.map(profile => html`
-
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}${command(profile)}${profile.type === 'ssh' ? 'Password saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
+
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}
${command(profile)}
${profile.type === 'ssh' ? 'Password saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
`)}
` : html`
Save a connection once

Keep SSH passwords and API tokens here. Your skills use the connection ID, so credentials stay out of instructions and chat.

`}

${icon('lock-keyhole', 'tc-icon--sm')}Saved on this server. Values are hidden from the page and filtered from helper output. Any agent with shell access can use these connections.

`; @@ -87,6 +87,7 @@ const T3CredentialsUI = (() => { const action = button.dataset.credentialAction, profile = data?.profiles.find(row => row.id === button.dataset.id); if (action === 'reload') { void load(); return; } if (action === 'add') { openEditor(); return; } + if (action === 'copy' && profile) { void Kit.copy(command(profile), button, 'Skill command copied'); return; } if (!profile || busy.has(profile.id) || error) return; if (action === 'edit') { openEditor(profile); return; } const revision = data.revision; diff --git a/docker/setup/console.css b/docker/setup/console.css index d8f94fb2..d12429e0 100644 --- a/docker/setup/console.css +++ b/docker/setup/console.css @@ -3094,6 +3094,9 @@ body[data-console-route="files"]:has(.tc-layer) .tc-toaster { visibility: hidden .tc-credential-main strong { font-size: 14px; overflow-wrap: anywhere; } .tc-credential-address, .tc-credential-command { overflow-wrap: anywhere; } .tc-credential-command { font-size: 12px; color: var(--fg-muted); } +.tc-credential-usage { display: flex; align-items: center; gap: 8px; } +.tc-credential-usage .tc-copyfield-value { min-width: 0; white-space: normal; overflow-wrap: anywhere; } +.tc-credential-usage .tc-btn { flex: none; } .tc-credential-actions { display: flex; gap: 8px; flex-wrap: wrap; } .tc-credential-note { display: flex; align-items: flex-start; gap: 8px; margin-top: 16px; } .tc-credential-note svg { flex: 0 0 auto; margin-top: 2px; } @@ -3108,7 +3111,7 @@ body[data-console-route="files"]:has(.tc-layer) .tc-toaster { visibility: hidden .tc-credential-actions { margin-left: 44px; } .tc-credential-toolbar > .tc-small { flex-basis: 100%; } } -.tc-root[data-density="touch"] :is(.tc-credential-actions, .tc-credential-toolbar, .tc-credential-editor .tc-dialog-foot) .tc-btn { min-height: var(--touch); min-width: var(--touch); } +.tc-root[data-density="touch"] :is(.tc-credential-actions, .tc-credential-toolbar, .tc-credential-usage, .tc-credential-editor .tc-dialog-foot) .tc-btn { min-height: var(--touch); min-width: var(--touch); } @media (max-width: 1023.98px) { .tc-layer--center > .tc-credential-editor { width: 100%; max-width: none; } } diff --git a/docs/server-credentials.md b/docs/server-credentials.md index ae8900da..28598ee5 100644 --- a/docs/server-credentials.md +++ b/docs/server-credentials.md @@ -26,6 +26,10 @@ a changed key. Verify first-use host identity on a trusted network. ## Use from an agent or terminal +Use the copy button beside a connection's command to paste it into a skill. +It copies only the helper command and connection ID. Replace the example remote +command or API path with the operation your skill needs. + These commands are installed in both image variants: ```sh diff --git a/scripts/credentials-ui-audit.mjs b/scripts/credentials-ui-audit.mjs index 82865a12..0b60abf1 100644 --- a/scripts/credentials-ui-audit.mjs +++ b/scripts/credentials-ui-audit.mjs @@ -25,6 +25,11 @@ try { const errors = [], responses = []; page.on('pageerror', error => errors.push(error.message)); page.on('response', response => { if (/\/credentials(?:\/|$)/.test(new URL(response.url()).pathname)) responses.push(response.text().catch(() => '')); }); await page.addInitScript(value => localStorage.setItem('t3-console-theme', value), theme); + await page.addInitScript(() => { + Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { + writeText: async text => { window.__copiedSkillCommand = text; }, + } }); + }); await page.route('**/*', route => { const url = new URL(route.request().url()); if (url.pathname.endsWith('/status')) return route.fulfill({ json: statusFor('ready') }); @@ -55,6 +60,12 @@ try { await capture('saved'); assert.equal((await target.content()).includes(secret), false); assert.equal((await target.content()).includes(token), false); + for (const [label, expected] of [['HomeServer', 't3-ssh homeserver -- uptime'], ['Home Assistant API', 't3-api homeassistant GET ""']]) { + await target.getByRole('button', { name: 'Copy skill command for ' + label, exact: true }).click(); + const copied = await target.evaluate(() => window.__copiedSkillCommand); + assert.equal(copied, expected); + assert.equal(copied.includes(secret), false); assert.equal(copied.includes(token), false); + } await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).click(); assert.equal(await target.locator('#credential-secret').inputValue(), ''); assert.equal(await target.getByLabel('Connection ID', { exact: true }).isDisabled(), true); From c68c7e154b07944406a939ec09154d0f0014fef9 Mon Sep 17 00:00:00 2001 From: 0libote <79215282+0libote@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:06:14 +0000 Subject: [PATCH 4/8] feat: generalize saved credentials for SSH and HTTP APIs --- README.md | 2 +- docker/setup/client/credentials.js | 21 ++-- docker/setup/client/routes.js | 2 +- docker/setup/credentials.mjs | 28 ++++- docker/setup/credentials/cli.mjs | 6 +- docker/setup/credentials/run.mjs | 23 ++-- docs/server-credentials.md | 139 ++++++++++++---------- examples/skills/server-ssh/SKILL.md | 15 +++ examples/skills/service-api/SKILL.md | 16 +++ examples/skills/ssh-ha/SKILL.md | 19 --- examples/skills/ssh/SKILL.md | 14 --- scripts/credentials-smoke.mjs | 6 +- scripts/credentials-ui-audit.mjs | 51 ++++++-- scripts/fixtures/console/credentials.json | 6 +- tests/credentials-api.test.mjs | 16 +-- tests/credentials.test.mjs | 77 +++++++++--- 16 files changed, 277 insertions(+), 164 deletions(-) create mode 100644 examples/skills/server-ssh/SKILL.md create mode 100644 examples/skills/service-api/SKILL.md delete mode 100644 examples/skills/ssh-ha/SKILL.md delete mode 100644 examples/skills/ssh/SKILL.md diff --git a/README.md b/README.md index c1ebd004..f6532a27 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ instead. Details: [Reaching the server from a phone](docs/remote-access.md). | [Upgrading T3 Code](docs/t3code-updates.md) | Stable and Nightly, auto-update, rollback | | [Toolchains](docs/toolchains.md) | Go, Rust and friends, any mise tool, per-project versions | | [Source control](docs/source-control.md) | gh, glab, fj, tea and az sign-in | -| [Server credentials](docs/server-credentials.md) | Saved SSH passwords and API tokens, used by name without putting values in chat | +| [Server credentials](docs/server-credentials.md) | Saved SSH passwords and API keys, used by name without putting values in chat | | [Publishing a port](docs/ports.md) | Public URLs for dev servers | | [Giving agents a browser](docs/agent-browser.md) | T3's server browser and the browser MCP servers | | [Context management](docs/context-management.md) | Global `AGENTS.md` and the shared skill library | diff --git a/docker/setup/client/credentials.js b/docker/setup/client/credentials.js index fd1638eb..d5546114 100644 --- a/docker/setup/client/credentials.js +++ b/docker/setup/client/credentials.js @@ -22,32 +22,36 @@ const T3CredentialsUI = (() => { else error = response.error || 'Could not load saved connections.'; loading = false; paint(); }; - const command = profile => profile.type === 'ssh' ? 't3-ssh ' + profile.id + ' -- uptime' : 't3-api ' + profile.id + ' GET ""'; + const command = profile => profile.type === 'ssh' ? 't3-ssh ' + profile.id + ' -- uptime' : 't3-api ' + profile.id + ' GET ' + T3McpCommand.quote(profile.testPath || ''); const body = () => html`
${data ? T3Model.plural(data.profiles.length, 'saved connection') : 'Saved connections'}
${error ? html`` : ''} ${!data ? html`
${loading ? 'Loading connections…' : 'Connections unavailable'}
` : data.profiles.length ? html`
${data.profiles.map(profile => html`
-
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}
${command(profile)}
${profile.type === 'ssh' ? 'Password saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
+
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}
${command(profile)}
${profile.type === 'ssh' ? 'Password saved' : profile.authType === 'header' ? 'Header key saved' : profile.authType === 'query' ? 'Query key saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
-
`)}
` : html`
Save a connection once

Keep SSH passwords and API tokens here. Your skills use the connection ID, so credentials stay out of instructions and chat.

`} + `)}` : html`
Save a connection once

Keep SSH passwords and API keys here. Your skills use the connection ID, so credentials stay out of instructions and chat.

`}

${icon('lock-keyhole', 'tc-icon--sm')}Saved on this server. Values are hidden from the page and filtered from helper output. Any agent with shell access can use these connections.

`; const openEditor = profile => { if (editor || !data || error || loading) return; notice?.close(); notice = null; - const view = { original: profile, revision: data.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '' }, busy: false, error: null }; + const view = { original: profile, revision: data.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '', authType: 'bearer', authName: 'X-API-Key', authPrefix: '', testPath: '' }, busy: false, error: null }; editor = view; - const field = (key, label, options = {}) => html`
${options.hint ? html`

${options.hint}

` : ''}
`; + const field = (key, label, options = {}) => html`
${options.hint ? html`

${options.hint}

` : ''}
`; const markup = () => html`

${profile ? 'Edit connection' : 'Add connection'}

${profile ? 'Leave the secret blank to keep its saved value.' : 'Save the login here, then use its connection ID in your skills.'}

${field('label', 'Name', { max: 120 })} ${field('id', 'Connection ID', { locked: Boolean(profile), max: 64, hint: 'Lowercase letters, numbers and hyphens. Used in helper commands.' })} -
- ${view.draft.type === 'ssh' ? html`${field('host', 'Host', { max: 253 })}
${field('username', 'Username', { max: 64 })}${field('port', 'Port', { type: 'number' })}
` : field('baseUrl', 'API base URL', { max: 2048, hint: 'Include the API path, for example http://homeassistant.local/api/.' })} -

${profile ? 'A value is saved. Enter a replacement only if you want to change it.' : 'This value will not appear in the saved connection details.'}

+
+ ${view.draft.type === 'ssh' ? html`${field('host', 'Host', { max: 253 })}
${field('username', 'Username', { max: 64 })}${field('port', 'Port', { type: 'number' })}
` : html` + ${field('baseUrl', 'API base URL', { max: 2048, hint: 'Include the API version or base path, for example https://api.example.com/v1/.' })} +
+ ${view.draft.authType === 'header' ? html`${field('authName', 'Header name', { max: 128, hint: 'For example X-API-Key, api-key or Authorization.' })}${field('authPrefix', 'Value prefix (optional)', { max: 128, required: false, hint: 'For example Token. Leave blank to send the key as the complete header value.' })}` : view.draft.authType === 'query' ? field('authName', 'Query parameter name', { max: 128, hint: 'For APIs that require a key in the URL. Prefer a header when supported.' }) : ''} + ${field('testPath', 'Test path (optional)', { max: 2048, required: false, hint: 'A relative GET endpoint that requires authentication; blank uses the base URL.' })}`} +

${profile ? 'A value is saved. Enter a replacement only if you want to change it.' : 'This value will not appear in the saved connection details.'}

${view.error ? html`` : ''}
`; const close = () => { if (!view.busy) view.layer.close(); }; @@ -61,6 +65,7 @@ const T3CredentialsUI = (() => { }); view.layer.panel.addEventListener('change', event => { if (event.target.dataset.credentialField === 'type' && !view.busy) { view.draft.type = event.target.value; view.layer.render(); } + if (event.target.dataset.credentialField === 'authType' && !view.busy) { view.draft.authType = event.target.value; view.draft.authName = event.target.value === 'query' ? 'api_key' : 'X-API-Key'; view.draft.authPrefix = ''; view.layer.render(); } }); view.layer.panel.addEventListener('click', event => { if (event.target.closest('[data-credential-cancel]')) close(); }); view.layer.panel.addEventListener('submit', async event => { diff --git a/docker/setup/client/routes.js b/docker/setup/client/routes.js index be03cf69..79a7dafd 100644 --- a/docker/setup/client/routes.js +++ b/docker/setup/client/routes.js @@ -28,7 +28,7 @@ const T3Routes = (() => { { route: 'files', title: 'Files', icon: 'folder', key: 'f', group: 'tools', summary: 'Your projects, your home folder and what fills the disk.', doc: 'files.md' }, { route: 'credentials', title: 'Server credentials', icon: 'key-round', key: 'c', group: 'tools', - summary: 'SSH passwords and API tokens your agents can use by name.', doc: 'server-credentials.md' }, + summary: 'SSH passwords and API keys your agents can use by name.', doc: 'server-credentials.md' }, { route: 'toolchains', title: 'Toolchains', icon: 'wrench', key: 't', group: 'tools', summary: 'Languages and tools on every agent’s path, at exact versions.', doc: 'toolchains.md' }, { route: 'sourcecontrol', title: 'Source control', icon: 'git-pull-request', key: 's', group: 'tools', diff --git a/docker/setup/credentials.mjs b/docker/setup/credentials.mjs index 8a784c4e..aff52c32 100644 --- a/docker/setup/credentials.mjs +++ b/docker/setup/credentials.mjs @@ -14,14 +14,22 @@ const object = value => value && typeof value === 'object' && !Array.isArray(val const text = (value, max) => typeof value === 'string' && value.isWellFormed() && value.length > 0 && value.length <= max && !/[\x00-\x1f\x7f]/.test(value); export const credentialDirectory = (env = process.env) => path.join(env.T3CODE_HOME || path.join(env.HOME || '/home/t3', '.t3'), 'server-credentials'); +export function apiTarget(profile, relative) { + if (profile.type !== 'api') throw new CredentialError('Choose an API connection.'); + if (typeof relative !== 'string' || relative.length > 2048 || !relative.isWellFormed() || /[\x00-\x1f\x7f]/.test(relative) || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) throw new CredentialError('Use a path relative to the saved API address, such as projects/123.'); + const base = new URL(profile.baseUrl), target = new URL(relative || '.', base); + if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.username || target.password || target.hash) throw new CredentialError('The request must stay inside the saved API address.'); + return target; +} + function normalize(input, previous) { if (!object(input)) fail('Enter connection details.'); if (!text(input.id, 64) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.id)) fail('Use up to 64 lowercase letters, numbers and single hyphens for the connection ID.'); if (!text(input.label, 120) || !input.label.trim()) fail('Enter a connection name of up to 120 characters.'); - if (!['ssh', 'api'].includes(input.type)) fail('Choose SSH password or API token.'); + if (!['ssh', 'api'].includes(input.type)) fail('Choose SSH password or API key / token.'); if (previous && previous.type !== input.type) fail('Create a new connection to change its type.'); const secret = input.secret === undefined || input.secret === '' ? previous?.secret : input.secret; - if (!text(secret, 8192)) fail('Enter a password or token of up to 8192 characters, without line breaks.'); + if (!text(secret, 8192)) fail('Enter a password or API key of up to 8192 characters, without line breaks.'); const profile = { id: input.id, label: input.label.trim(), type: input.type, secret }; if (input.type === 'ssh') { if (!text(input.host, 253) || !/^[a-zA-Z0-9][a-zA-Z0-9.:-]*$/.test(input.host)) fail('Enter a hostname or IP address, without a username or port.'); @@ -34,6 +42,22 @@ function normalize(input, previous) { if (!text(input.baseUrl, 2048) || !['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) fail('Use an HTTP or HTTPS API address without credentials, a query or a fragment.'); if (!url.pathname.endsWith('/')) url.pathname += '/'; profile.baseUrl = url.href; + profile.authType = input.authType ?? previous?.authType ?? 'bearer'; + if (!['bearer', 'header', 'query'].includes(profile.authType)) fail('Choose bearer token, custom header or query parameter authentication.'); + if (profile.authType !== 'bearer') { + const name = input.authName ?? previous?.authName; + if (!text(name, 128)) fail('Enter an authentication header or parameter name of up to 128 characters.'); + if (profile.authType === 'header') { + try { new Headers({ [name]: 'placeholder' }); } catch { fail('Enter a valid HTTP header name.'); } + if (['host', 'content-length', 'transfer-encoding', 'connection', 'upgrade', 'expect', 'trailer', 'te', 'accept', 'content-type'].includes(name.toLowerCase())) fail('Choose an authentication header, not a request transport or content header.'); + const prefix = input.authPrefix ?? previous?.authPrefix ?? ''; + if (typeof prefix !== 'string' || prefix.length > 128 || /[^\x20-\x7e]/.test(prefix)) fail('Use up to 128 printable ASCII characters for the optional header prefix.'); + profile.authPrefix = prefix.trim(); + } + profile.authName = name; + } + profile.testPath = input.testPath ?? previous?.testPath ?? ''; + apiTarget(profile, profile.testPath); } return profile; } diff --git a/docker/setup/credentials/cli.mjs b/docker/setup/credentials/cli.mjs index 29d7ca61..febb6fc2 100644 --- a/docker/setup/credentials/cli.mjs +++ b/docker/setup/credentials/cli.mjs @@ -8,9 +8,9 @@ const USAGE = `Use saved credentials without putting their values in commands: Manage connections in Setup → Server credentials. For JSON request bodies, use --stdin and pipe the body into t3-api. Examples: - t3-ssh homeserver -- uptime - t3-api homeassistant GET states/light.kitchen - printf '%s' '{"entity_id":"light.kitchen"}' | t3-api homeassistant POST services/light/turn_on --stdin + t3-ssh build-server -- uptime + t3-api project-api GET projects/demo-project + printf '%s' '{"name":"demo-project"}' | t3-api project-api POST projects --stdin `; async function main() { diff --git a/docker/setup/credentials/run.mjs b/docker/setup/credentials/run.mjs index af1ce421..394afb47 100644 --- a/docker/setup/credentials/run.mjs +++ b/docker/setup/credentials/run.mjs @@ -1,12 +1,13 @@ import { spawn } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { Readable } from 'node:stream'; -import { CredentialError } from '../credentials.mjs'; +import { CredentialError, apiTarget } from '../credentials.mjs'; +export { apiTarget } from '../credentials.mjs'; // Keep matches that straddle output chunks private too. Encoded JSON/API // echoes and URL-encoded diagnostics are scrubbed alongside the literal value. export function outputFilter(secret, write) { - const values = [...new Set([secret, JSON.stringify(secret).slice(1, -1), encodeURIComponent(secret), Buffer.from(secret).toString('base64')])].filter(Boolean).sort((a, b) => b.length - a.length); + const values = [...new Set([secret, JSON.stringify(secret).slice(1, -1), encodeURIComponent(secret), new URLSearchParams([['', secret]]).toString().slice(1), Buffer.from(secret).toString('base64')])].filter(Boolean).sort((a, b) => b.length - a.length); const pattern = new RegExp(values.map(value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g'); const keep = Math.max(...values.map(value => value.length)) - 1; let pending = ''; @@ -52,23 +53,19 @@ export async function sshRequest(profile, command, { stdout = process.stdout, st return code; } -export function apiTarget(profile, relative) { - if (profile.type !== 'api') throw new CredentialError('Choose an API token connection.'); - if (typeof relative !== 'string' || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) throw new CredentialError('Use a path relative to the saved API address, such as states/light.kitchen.'); - const base = new URL(profile.baseUrl), target = new URL(relative || '.', base); - if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.username || target.password || target.hash) throw new CredentialError('The request must stay inside the saved API address.'); - return target; -} - export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, probe = false, signal = AbortSignal.timeout(30000) } = {}) { if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new CredentialError('Use GET, HEAD, POST, PUT, PATCH or DELETE.'); const target = apiTarget(profile, relative); try { + const headers = new Headers({ accept: 'application/json', ...(body === undefined ? {} : { 'content-type': 'application/json' }) }); + if (profile.authType === 'query') target.searchParams.set(profile.authName, profile.secret); + else if (profile.authType === 'header') headers.set(profile.authName, (profile.authPrefix ? profile.authPrefix + ' ' : '') + profile.secret); + else headers.set('authorization', 'Bearer ' + profile.secret); const response = await fetch(target, { method, redirect: 'error', signal, - headers: { authorization: 'Bearer ' + profile.secret, accept: 'application/json', ...(body === undefined ? {} : { 'content-type': 'application/json' }) }, body }); + headers, body }); if (probe) { await response.body?.cancel(); - if (!response.ok) throw new CredentialError('The API did not accept the request (HTTP ' + response.status + '). Check the address and token.', 502); + if (!response.ok) throw new CredentialError('The API did not accept the request (HTTP ' + response.status + '). Check the address and authentication settings.', 502); } else if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); return response.ok ? 0 : 1; } catch (error) { @@ -79,5 +76,5 @@ export async function apiRequest(profile, method, relative, { body, stdout = pro export const testCredential = (profile, { signal = AbortSignal.timeout(15000) } = {}) => { return profile.type === 'ssh' ? sshRequest(profile, ['true'], { probe: true, stdin: 'ignore', signal }) - : apiRequest(profile, 'GET', '', { probe: true, signal }); + : apiRequest(profile, 'GET', profile.testPath || '', { probe: true, signal }); }; diff --git a/docs/server-credentials.md b/docs/server-credentials.md index 28598ee5..ec713048 100644 --- a/docs/server-credentials.md +++ b/docs/server-credentials.md @@ -1,30 +1,49 @@ # Server credentials -**Setup → Server credentials** keeps SSH passwords and API bearer tokens out -of skill files and agent prompts. Save a connection, then give the agent its -connection ID. The page supports adding, editing, testing and deleting connections -on desktop and phone, including inside T3 Code's Settings → Setup dialog. +**Setup → Server credentials** saves SSH passwords and API keys for servers, +internal tools and third-party services. Agents use a connection ID through +`t3-ssh` or `t3-api`, so the secret stays out of skill files and normal prompts. +The page supports adding, editing, testing and deleting connections on desktop +and phone, including inside T3 Code's Settings → Setup dialog. -Choose **Add connection**, enter a name and a stable ID such as `homeserver`, -then choose a type: +Choose **Add connection**, enter a name and a stable ID such as `build-server` +or `project-api`, then choose a type: - **SSH password:** hostname or IP, username, port and password. -- **API bearer token:** the full API base URL and token. For Home Assistant, - include `/api/`, for example `http://homeassistant.local/api/`. +- **API key or token:** the full API base URL, authentication settings and secret. + Include any version or base path, such as `https://api.example.com/v1/`. -Saved passwords and tokens are never returned to the browser. **Edit** changes -connection details and can replace the secret; leave the secret blank to keep -its existing value. A stale editor cannot overwrite changes from another -window: close it, reload the list, and reopen the connection before saving again. +API connections support these authentication formats: + +| Authentication | Settings | Request | +| --- | --- | --- | +| Bearer token | Saved token | `Authorization: Bearer ` | +| Custom header | Header name, optional value prefix | `X-API-Key: `, `api-key: `, or `Authorization: Token ` | +| Query parameter | Parameter name | `?api_key=` or the name your service requires | + +Choose the format required by the service. Query keys become part of the +request URL and may appear in the service's own logs; prefer headers when the +service supports them. OAuth sign-in flows, request signing and websocket +protocols are outside the HTTP helper's scope. + +Saved passwords and keys are never returned to the credentials page. **Edit** +changes connection details or replaces the secret; leave the secret blank to +keep its saved value. A stale editor cannot overwrite another window's changes. +Close it, reload the list and reopen the connection before saving again. Connection IDs and types stay fixed; create another entry to change them. +Existing API connections continue to use bearer authentication until edited. + +## Test a connection **Test** uses the saved login: SSH runs `true`, and API sends a GET to the saved -base URL. It returns only success or a short error, without the response body. -An API whose base URL does not accept GET may fail this test even when its token -works for other endpoints. SSH remembers a new host key on first use and refuses -a changed key. Verify first-use host identity on a trusted network. +**Test path**. Use a relative endpoint that requires authentication, such as +`account` or `user`. A blank test path uses the base URL. Tests return success +or a short error without the response body. A public endpoint may succeed even +with an invalid key, and an endpoint that rejects GET cannot serve as this test. +SSH remembers a new host key on first use and refuses a changed key. Verify +first-use host identity on a trusted network. -## Use from an agent or terminal +## Use from a skill or terminal Use the copy button beside a connection's command to paste it into a skill. It copies only the helper command and connection ID. Replace the example remote @@ -33,48 +52,42 @@ command or API path with the operation your skill needs. These commands are installed in both image variants: ```sh -t3-ssh homeserver -- uptime -t3-ssh homeassistant-ssh -- 'ha core info' -t3-api homeassistant GET states/light.kitchen -printf '%s' '{"entity_id":"light.kitchen"}' | - t3-api homeassistant POST services/light/turn_on --stdin +t3-ssh build-server -- uptime +t3-ssh staging-server -- 'systemctl status app' +t3-api project-api GET projects +printf '%s' '{"name":"demo-project"}' | t3-api project-api POST projects --stdin ``` `t3-ssh` runs a non-interactive remote command. Supply a complete remote shell -command as one quoted argument when it includes pipelines or shell syntax. Its -stdin remains available for scripts, for example `t3-ssh homeserver -- bash -s`. -It uses password or keyboard-interactive authentication; multi-step challenges -and interactive terminal sessions are outside this helper's scope. +command as one quoted argument when it includes pipelines or shell syntax. +Stdin remains available for scripts, such as `t3-ssh build-server -- bash -s`. +The helper supports password or keyboard-interactive authentication, without +multi-step challenges or interactive terminal sessions. `t3-api` accepts GET, HEAD, POST, PUT, PATCH and DELETE. Paths are relative to the -saved base URL, without a leading slash. The optional `--stdin` supplies a JSON -body of at most 1 MiB. Requests stay under that base URL; redirects are refused -so a token cannot be forwarded to another destination. Responses go to stdout; -HTTP failures return a nonzero exit status. This helper covers REST calls, not -Home Assistant's websocket API. - -Both helpers read their credentials internally, without including their values -in command arguments. Matching literal, JSON-escaped, URL-encoded and Base64 -values are filtered from response output. This avoids accidental echoes of the -stored credential; it cannot recognize every possible transformation or prevent -an agent deliberately reading files with its shell. +saved base URL, without a leading slash. Optional `--stdin` supplies a JSON body +of at most 1 MiB. Requests stay under the saved base URL and refuse redirects. +Responses go to stdout; HTTP failures return a nonzero exit status. The helper +injects the saved secret using the connection's authentication settings, so +commands stay the same when a service uses a different header or parameter. -## Move credentials out of skills +Both helpers filter matching literal, JSON-escaped, URL-encoded and Base64 +secret values from output. This covers accidental echoes of the saved value; +it cannot recognize every transformation or prevent an agent reading files +with its shell. -Create these three entries through the page: +## Move credentials out of skills -| Connection ID | Type | Purpose | -| --- | --- | --- | -| `homeserver` | SSH password | HomeServer commands | -| `homeassistant-ssh` | SSH password | Home Assistant SSH commands | -| `homeassistant` | API bearer token | Home Assistant REST API | +Save and test each connection through the page, then replace secrets in your +skills with helper commands. Generic SSH and API skill templates are in +[`examples/skills`](../examples/skills); adapt their IDs and operations to your +services. Install the image containing the helpers before switching existing +skills. Rotate credentials that previously appeared in chat or skill history; +deleting the text does not remove earlier copies. -Test each entry, then replace passwords and tokens in your skills with helper -commands. Example replacement skills are in -[`examples/skills`](../examples/skills). Keep any server-specific instructions -you still need. Install the image containing these helpers before switching -existing skills. Rotate credentials that previously appeared in chat or skill -history; deleting the text does not remove earlier copies. +Home Assistant is one example of a bearer-token API: use your instance's API +base URL ending in `/api/` and choose Bearer token authentication. It uses the +same API connection type as other services. ## Storage and access @@ -82,16 +95,16 @@ Connections are stored as plaintext JSON in `$T3CODE_HOME/server-credentials/credentials.json` (normally `/home/t3/.t3/server-credentials/credentials.json`). The directory is owner-only (0700) and the file is owner-only (0600). The default `/home/t3` volume keeps -them across restarts, image upgrades and recreations. A deployment that mounts -only `T3CODE_HOME` keeps them there too. Protect backups of this volume. - -The feature keeps credentials out of ordinary prompts and helper output. It is -not an encrypted vault or a permission boundary against an agent with shell -access. The authenticated console and helpers run as the same container user; -any process with that user's file access can read the saved values. SSH passes -the password to its askpass child through its private child environment. -Never request a credential dump in a chat or print that environment. - -The page uses the existing setup authentication and request protections, and -requires HTTPS or a trusted private connection like the rest of the setup console. -It does not put secrets in `/status`, downloadable skills or browser storage. +connections across restarts, image upgrades and recreations. Deployments that +mount only `T3CODE_HOME` keep them there too. Protect backups of this volume. + +The feature keeps secrets out of ordinary prompts and helper output. It does +not encrypt the store or isolate it from an agent with shell access. The console +and helpers run as the same container user, so any process with that user's file +access can read the saved values. SSH passes the password to its askpass child +through a child environment. Never request a credential dump in chat or print +that environment. + +The page uses the existing setup authentication and request protections. Use +HTTPS or a trusted private connection, as with the rest of the setup console. +Secrets are absent from `/status`, downloadable skills and browser storage. diff --git a/examples/skills/server-ssh/SKILL.md b/examples/skills/server-ssh/SKILL.md new file mode 100644 index 00000000..145262ff --- /dev/null +++ b/examples/skills/server-ssh/SKILL.md @@ -0,0 +1,15 @@ +--- +name: server-ssh +description: Use the saved build-server SSH connection when asked to administer that server. +--- + +Use the saved `build-server` connection for remote commands: + +```sh +t3-ssh build-server -- '' +``` + +The host, username, port and password are managed in Setup → Server credentials. +Change the connection ID in this example to match your server. If authentication +fails, check the saved connection. Do not read or print credential files or the +helper's child environment. diff --git a/examples/skills/service-api/SKILL.md b/examples/skills/service-api/SKILL.md new file mode 100644 index 00000000..a3a4b926 --- /dev/null +++ b/examples/skills/service-api/SKILL.md @@ -0,0 +1,16 @@ +--- +name: service-api +description: Use the saved project-api connection when asked to work with that service's API. +--- + +Use the saved `project-api` connection for HTTP API requests: + +```sh +t3-api project-api GET projects +printf '%s' '{"name":"demo-project"}' | t3-api project-api POST projects --stdin +``` + +Change the connection ID and paths in this example to match your service. Paths +are relative to its saved base URL, without a leading slash. Authentication, +including the header or query parameter name, is configured in Setup → Server +credentials. Do not read or print credential files. Use `--stdin` for JSON bodies. diff --git a/examples/skills/ssh-ha/SKILL.md b/examples/skills/ssh-ha/SKILL.md deleted file mode 100644 index 7c869156..00000000 --- a/examples/skills/ssh-ha/SKILL.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: ssh-ha -description: Use Home Assistant SSH or its REST API when explicitly asked to work on Home Assistant. ---- - -Use the saved connections; no password or API token belongs in this skill. - -```sh -t3-ssh homeassistant-ssh -- 'ha core info' -t3-api homeassistant GET states/light.kitchen -printf '%s' '{"entity_id":"light.kitchen"}' | - t3-api homeassistant POST services/light/turn_on --stdin -``` - -`homeassistant-ssh` is the SSH login. `homeassistant` is the API bearer token -and base URL, including `/api/`. The port is part of that saved URL. -Manage both in Setup → Server credentials. Do not read or print credential files -or the helper's child environment. The API helper handles REST requests; it does -not handle Home Assistant's websocket automation traces. diff --git a/examples/skills/ssh/SKILL.md b/examples/skills/ssh/SKILL.md deleted file mode 100644 index 680984c5..00000000 --- a/examples/skills/ssh/SKILL.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: ssh -description: SSH to HomeServer when explicitly asked to use that server. ---- - -Use the saved `homeserver` SSH connection: - -```sh -t3-ssh homeserver -- '' -``` - -Connection details and the password are managed in Setup → Server credentials. -If the connection is missing or authentication fails, ask the user to check that -page. Do not read or print credential files or the helper's child environment. diff --git a/scripts/credentials-smoke.mjs b/scripts/credentials-smoke.mjs index b61beeba..e2ccaf2f 100644 --- a/scripts/credentials-smoke.mjs +++ b/scripts/credentials-smoke.mjs @@ -16,7 +16,7 @@ const request = async (route, body) => { const text = await response.text(); assert.equal(text.includes(secret), false); assert.equal(response.status, 200, text); return JSON.parse(text); }; const server = createServer((req, res) => { - assert.equal(req.headers.authorization, 'Bearer ' + secret); + assert.equal(req.headers['x-api-key'], secret); res.end(JSON.stringify({ status: 'ok', echo: secret })); }); server.listen(0, '127.0.0.1'); await once(server, 'listening'); @@ -26,11 +26,11 @@ try { await access('/opt/t3-setup/credentials/askpass.sh', constants.X_OK); for (const cli of ['t3-ssh', 't3-api']) assert.match((await run('/usr/local/bin/' + cli, ['--help'])).stdout, /Manage connections/); let snapshot = await request('/credentials'); - await request('/credentials/create', { revision: snapshot.revision, profile: { id, label: 'Disposable image check', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } }); + await request('/credentials/create', { revision: snapshot.revision, profile: { id, label: 'Disposable image check', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', authType: 'header', authName: 'X-API-Key', testPath: 'account', secret } }); created = true; snapshot = await request('/credentials'); assert.equal(snapshot.profiles.find(profile => profile.id === id).hasSecret, true); await request('/credentials/test', { id, revision: snapshot.revision }); - const { stdout, stderr } = await run('/usr/local/bin/t3-api', [id, 'GET', 'states']); + const { stdout, stderr } = await run('/usr/local/bin/t3-api', [id, 'GET', 'projects']); assert.deepEqual(JSON.parse(stdout), { status: 'ok', echo: '[redacted]' }); assert.equal(stderr, ''); console.log('PASS saved API credentials and installed SSH/API helpers'); } finally { diff --git a/scripts/credentials-ui-audit.mjs b/scripts/credentials-ui-audit.mjs index 0b60abf1..b843b96b 100644 --- a/scripts/credentials-ui-audit.mjs +++ b/scripts/credentials-ui-audit.mjs @@ -50,23 +50,50 @@ try { await dialog.waitFor(); await target.getByLabel('Name', { exact: true }).fill(label); await target.getByLabel('Connection ID', { exact: true }).fill(id); await target.getByLabel('Connection type').selectOption(type); - if (type === 'ssh') { await target.getByLabel('Host', { exact: true }).fill('192.0.2.10'); await target.getByLabel('Username', { exact: true }).fill(id === 'homeserver' ? 'oliver' : 'root'); } - else await target.getByLabel('API base URL').fill('http://192.0.2.20/api/'); + if (type === 'ssh') { await target.getByLabel('Host', { exact: true }).fill('192.0.2.10'); await target.getByLabel('Username', { exact: true }).fill(id === 'build-server' ? 'deploy' : 'root'); } + else { + await target.getByLabel('API base URL').fill('https://api.example.com/v1/'); + await target.getByLabel('Authentication', { exact: true }).selectOption('header'); + await target.getByLabel('Header name', { exact: true }).fill('X-API-Key'); + await target.getByLabel('Test path (optional)', { exact: true }).fill('account'); + } await target.locator('#credential-secret').fill(type === 'ssh' ? secret : token); await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); await dialog.waitFor({ state: 'hidden' }); await target.locator(`[data-key="credential-${id}"]`).waitFor(); }; - await add('homeserver', 'HomeServer'); await add('homeassistant-ssh', 'Home Assistant SSH'); await add('homeassistant', 'Home Assistant API', 'api'); + await add('build-server', 'Build server'); await add('staging-server', 'Staging server'); await add('project-api', 'Project API', 'api'); await capture('saved'); + await target.getByRole('button', { name: 'Edit Project API', exact: true }).click(); + assert.equal(await target.getByLabel('Authentication', { exact: true }).inputValue(), 'header'); + await target.locator('#credential-secret').fill(token); + await target.getByLabel('Header name', { exact: true }).fill('Custom-Key'); + await target.getByLabel('Authentication', { exact: true }).selectOption('query'); + assert.equal(await target.getByLabel('Query parameter name', { exact: true }).inputValue(), 'api_key'); + assert.equal(await target.locator('#credential-secret').inputValue(), token); + await capture('query-auth'); + await target.getByLabel('Authentication', { exact: true }).selectOption('header'); + assert.equal(await target.locator('#credential-secret').inputValue(), token); + await target.getByLabel('Header name', { exact: true }).fill('Authorization'); + await target.getByLabel('Value prefix (optional)', { exact: true }).fill('Token'); + await capture('header-auth'); + await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); + await dialog.waitFor({ state: 'hidden' }); + await target.getByRole('button', { name: 'Reload', exact: true }).waitFor({ state: 'visible' }); + await target.getByRole('button', { name: 'Edit Project API', exact: true }).click(); + assert.equal(await target.getByLabel('Header name', { exact: true }).inputValue(), 'Authorization'); + assert.equal(await target.getByLabel('Value prefix (optional)', { exact: true }).inputValue(), 'Token'); + assert.equal(await target.locator('#credential-secret').inputValue(), ''); + await dialog.getByRole('button', { name: 'Cancel', exact: true }).click(); + assert.equal((await target.content()).includes(secret), false); assert.equal((await target.content()).includes(token), false); - for (const [label, expected] of [['HomeServer', 't3-ssh homeserver -- uptime'], ['Home Assistant API', 't3-api homeassistant GET ""']]) { + for (const [label, expected] of [['Build server', 't3-ssh build-server -- uptime'], ['Project API', 't3-api project-api GET account']]) { await target.getByRole('button', { name: 'Copy skill command for ' + label, exact: true }).click(); const copied = await target.evaluate(() => window.__copiedSkillCommand); assert.equal(copied, expected); assert.equal(copied.includes(secret), false); assert.equal(copied.includes(token), false); } - await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).click(); + await target.getByRole('button', { name: 'Edit Build server', exact: true }).click(); assert.equal(await target.locator('#credential-secret').inputValue(), ''); assert.equal(await target.getByLabel('Connection ID', { exact: true }).isDisabled(), true); assert.equal(await target.getByLabel('Connection type').isDisabled(), true); @@ -77,7 +104,7 @@ try { await capture('edit'); // An overlapping editor must not silently replace another window's edit. const current = await (await f.request('/credentials')).json(); - const old = current.profiles.find(profile => profile.id === 'homeserver'); + const old = current.profiles.find(profile => profile.id === 'build-server'); await f.request('/credentials/save', { profile: { ...old, label: 'Updated elsewhere' }, revision: current.revision }); await target.locator('#credential-secret').fill('replacement-fixture-password'); await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); @@ -90,7 +117,7 @@ try { await target.getByRole('button', { name: 'Reload', exact: true }).click(); await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).waitFor(); await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).click(); - await target.getByLabel('Name', { exact: true }).fill('HomeServer'); + await target.getByLabel('Name', { exact: true }).fill('Build server'); // Saving twice while the request is pending still issues exactly one write. let release, started, saves = 0; const gate = new Promise(resolve => { release = resolve; }); @@ -102,19 +129,19 @@ try { await target.locator('#credential-secret').press('Enter'); await page.keyboard.press('Escape'); assert.equal(await dialog.count(), 1); assert.equal(await dialog.getByRole('button', { name: 'Cancel', exact: true }).isDisabled(), true); release(); await dialog.waitFor({ state: 'hidden' }); await page.unroute('**/credentials/save', intercept); - assert.equal(saves, 1); await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).waitFor(); + assert.equal(saves, 1); await target.getByRole('button', { name: 'Edit Build server', exact: true }).waitFor(); await page.route('**/credentials/test', route => route.fulfill({ json: { ok: true, message: 'Connection succeeded.' } })); - await target.getByRole('button', { name: 'Test Home Assistant API', exact: true }).click(); + await target.getByRole('button', { name: 'Test Project API', exact: true }).click(); await target.getByText('Connection succeeded', { exact: true }).waitFor(); const failRead = route => route.fulfill({ status: 500, json: { ok: false, error: 'Fixture read failed.' } }); await page.route('**/credentials', failRead); await target.getByRole('button', { name: 'Reload', exact: true }).click(); await target.getByRole('alert').waitFor(); - assert.equal(await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).isDisabled(), true); + assert.equal(await target.getByRole('button', { name: 'Edit Build server', exact: true }).isDisabled(), true); await capture('read-error'); await page.unroute('**/credentials', failRead); await target.getByRole('button', { name: 'Reload', exact: true }).click(); - await target.getByRole('button', { name: 'Delete Home Assistant SSH', exact: true }).click(); + await target.getByRole('button', { name: 'Delete Staging server', exact: true }).click(); await target.getByRole('alertdialog').getByRole('button', { name: 'Delete connection', exact: true }).click(); - await target.locator('[data-key="credential-homeassistant-ssh"]').waitFor({ state: 'hidden' }); + await target.locator('[data-key="credential-staging-server"]').waitFor({ state: 'hidden' }); assert.equal(await target.evaluate(() => document.documentElement.scrollWidth > innerWidth), false); for (const response of await Promise.all(responses)) for (const value of [secret, token, 'replacement-fixture-password']) assert.equal(response.includes(value), false); assert.deepEqual(errors, []); await capture('after-delete'); diff --git a/scripts/fixtures/console/credentials.json b/scripts/fixtures/console/credentials.json index 5aa06ff5..dc3b185b 100644 --- a/scripts/fixtures/console/credentials.json +++ b/scripts/fixtures/console/credentials.json @@ -2,8 +2,8 @@ "ok": true, "revision": "fixture-credentials", "profiles": [ - { "id": "homeserver", "label": "HomeServer", "type": "ssh", "host": "192.0.2.10", "username": "oliver", "port": 22, "hasSecret": true }, - { "id": "homeassistant-ssh", "label": "Home Assistant SSH", "type": "ssh", "host": "192.0.2.20", "username": "root", "port": 22, "hasSecret": true }, - { "id": "homeassistant", "label": "Home Assistant API", "type": "api", "baseUrl": "http://192.0.2.20/api/", "hasSecret": true } + { "id": "build-server", "label": "Build server", "type": "ssh", "host": "192.0.2.10", "username": "deploy", "port": 22, "hasSecret": true }, + { "id": "staging-server", "label": "Staging server", "type": "ssh", "host": "192.0.2.20", "username": "root", "port": 22, "hasSecret": true }, + { "id": "project-api", "label": "Project API", "type": "api", "baseUrl": "https://api.example.com/v1/", "authType": "header", "authName": "X-API-Key", "authPrefix": "", "testPath": "account", "hasSecret": true } ] } diff --git a/tests/credentials-api.test.mjs b/tests/credentials-api.test.mjs index 679cf275..77df8dbf 100644 --- a/tests/credentials-api.test.mjs +++ b/tests/credentials-api.test.mjs @@ -18,7 +18,7 @@ test('credential HTTP boundary is authenticated, write-only and revision checked const initial = await (await f.request('/credentials')).json(); assert.deepEqual(initial.profiles, []); const secret = 'fixture-http-credential-456'; - const profile = { id: 'homeassistant-ssh', label: 'Home Assistant SSH', type: 'ssh', host: '192.0.2.2', username: 'root', port: 22, secret }; + const profile = { id: 'staging-server', label: 'Staging server', type: 'ssh', host: '192.0.2.2', username: 'root', port: 22, secret }; const created = await (await f.request('/credentials/create', { profile, revision: initial.revision })).json(); assert.equal(created.ok, true); assert.equal(JSON.stringify(created).includes(secret), false); const snapshotResponse = await f.request('/credentials'); @@ -40,7 +40,7 @@ test('credential HTTP boundary is authenticated, write-only and revision checked assert.equal(f.logs().includes(secret), false); }); -test('saved HA token works through the CLI and connection test without returning the token', { timeout: 20000 }, async t => { +test('saved API token works through the CLI and connection test without returning the token', { timeout: 20000 }, async t => { const f = await credentialsFixture(); t.after(f.close); const secret = 'fixture-api-token-789'; let target, failAuth = false; const server = createServer(async (req, res) => { @@ -53,21 +53,21 @@ test('saved HA token works through the CLI and connection test without returning server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); const initial = await (await f.request('/credentials')).json(); - const saved = await (await f.request('/credentials/create', { revision: initial.revision, profile: { id: 'homeassistant', label: 'Home Assistant API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } })).json(); - const probe = await f.request('/credentials/test', { id: 'homeassistant', revision: saved.revision }); + const saved = await (await f.request('/credentials/create', { revision: initial.revision, profile: { id: 'project-api', label: 'Project API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } })).json(); + const probe = await f.request('/credentials/test', { id: 'project-api', revision: saved.revision }); assert.equal(probe.status, 200); assert.equal((await probe.text()).includes(secret), false); failAuth = true; - const rejected = await f.request('/credentials/test', { id: 'homeassistant', revision: saved.revision }); + const rejected = await f.request('/credentials/test', { id: 'project-api', revision: saved.revision }); assert.equal(rejected.status, 502); assert.equal((await rejected.text()).includes(secret), false); failAuth = false; const helperEnv = { ...f.env, T3_INFRA_NODE: process.execPath, T3_CREDENTIAL_CLI: fileURLToPath(new URL('../docker/setup/credentials/cli.mjs', import.meta.url)) }; - const child = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-api', import.meta.url)), 'homeassistant', 'POST', 'services/light/turn_on', '--stdin'], { env: helperEnv, stdio: ['pipe', 'pipe', 'pipe'] }); + const child = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-api', import.meta.url)), 'project-api', 'POST', 'projects', '--stdin'], { env: helperEnv, stdio: ['pipe', 'pipe', 'pipe'] }); let out = '', err = ''; child.stdout.on('data', chunk => { out += chunk; }); child.stderr.on('data', chunk => { err += chunk; }); - child.stdin.end('{"entity_id":"light.kitchen"}'); + child.stdin.end('{"name":"demo-project"}'); const [code] = await once(child, 'close'); assert.equal(code, 0, err); assert.equal(err, ''); assert.deepEqual(JSON.parse(out), { message: '[redacted]', ok: true }); - assert.deepEqual(target, { url: '/api/services/light/turn_on', method: 'POST', body: '{"entity_id":"light.kitchen"}' }); + assert.deepEqual(target, { url: '/api/projects', method: 'POST', body: '{"name":"demo-project"}' }); const help = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-ssh', import.meta.url)), '--help'], { env: helperEnv, stdio: ['ignore', 'pipe', 'pipe'] }); let helpText = ''; help.stdout.on('data', chunk => { helpText += chunk; }); assert.equal((await once(help, 'close'))[0], 0); assert.match(helpText, /t3-ssh CONNECTION/); diff --git a/tests/credentials.test.mjs b/tests/credentials.test.mjs index c6e313f4..6aa34bda 100644 --- a/tests/credentials.test.mjs +++ b/tests/credentials.test.mjs @@ -10,7 +10,7 @@ import { createCredentialStore, credentialFailure } from '../docker/setup/creden import { outputFilter, apiRequest, apiTarget, sshRequest, testCredential } from '../docker/setup/credentials/run.mjs'; const secret = 'fixture-private-credential-123'; -const ssh = { id: 'homeserver', label: 'Home server', type: 'ssh', host: '192.0.2.1', username: 'oliver', port: 22, secret }; +const ssh = { id: 'build-server', label: 'Build server', type: 'ssh', host: '192.0.2.1', username: 'deploy', port: 22, secret }; async function fixture(t) { const root = await fs.mkdtemp(path.join(os.tmpdir(), 't3-credentials-')); const directory = path.join(root, 'credentials'); @@ -22,21 +22,21 @@ const create = async (store, profile) => store.save({ profile, revision: (await test('credentials persist privately and public reads never include saved values', async t => { const { directory, store } = await fixture(t); await create(store, ssh); - await create(store, { id: 'ha', label: 'Home Assistant API', type: 'api', baseUrl: 'http://192.0.2.2/api', secret: secret + '-token' }); + await create(store, { id: 'project-api', label: 'Project API', type: 'api', baseUrl: 'http://192.0.2.2/api', secret: secret + '-token' }); const snapshot = await createCredentialStore({ directory }).list(); assert.equal(snapshot.profiles.length, 2); assert.equal(snapshot.profiles[1].baseUrl, 'http://192.0.2.2/api/'); assert.equal(JSON.stringify(snapshot).includes(secret), false); - assert.equal((await store.forUse('homeserver')).secret, secret); + assert.equal((await store.forUse('build-server')).secret, secret); assert.equal((await fs.stat(directory)).mode & 0o777, 0o700); assert.equal((await fs.stat(path.join(directory, 'credentials.json'))).mode & 0o777, 0o600); const saved = await store.save({ profile: { ...ssh, secret: '', label: 'Renamed' }, revision: snapshot.revision }); - assert.equal((await store.forUse('homeserver')).secret, secret); + assert.equal((await store.forUse('build-server')).secret, secret); assert.equal(JSON.stringify(saved).includes(secret), false); await store.save({ profile: { ...ssh, secret: 'replacement-password' }, revision: saved.revision }); - assert.equal((await store.forUse('homeserver')).secret, 'replacement-password'); - await store.remove({ id: 'homeserver', revision: (await store.list()).revision }); - await assert.rejects(store.forUse('homeserver'), /not found/); + assert.equal((await store.forUse('build-server')).secret, 'replacement-password'); + await store.remove({ id: 'build-server', revision: (await store.list()).revision }); + await assert.rejects(store.forUse('build-server'), /not found/); assert.equal((await store.list()).profiles.length, 1); }); @@ -51,8 +51,8 @@ test('conflicting, duplicate and overlapping writes cannot overwrite another edi assert.deepEqual(outcomes.map(outcome => outcome.status), ['fulfilled', 'rejected']); assert.equal(outcomes[1].reason.status, 409); revision = (await store.list()).revision; - await assert.rejects(store.remove({ id: 'homeserver', revision: before.revision }), { status: 409 }); - assert.equal((await store.forUse('homeserver')).label, 'First'); + await assert.rejects(store.remove({ id: 'build-server', revision: before.revision }), { status: 409 }); + assert.equal((await store.forUse('build-server')).label, 'First'); }); test('invalid input and damaged stores fail without echoing or replacing credentials', async t => { @@ -80,8 +80,8 @@ test('invalid input and damaged stores fail without echoing or replacing credent }); test('output filtering masks literal and encoded values across every chunk boundary', () => { - for (const value of [secret, 'password-with-"quotes"&slashes\\and-more']) { - const variants = [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value), Buffer.from(value).toString('base64')]; + for (const value of [secret, 'password-with-"quotes"&slashes\\and-more', 'key +/~']) { + const variants = [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value), new URLSearchParams([['', value]]).toString().slice(1), Buffer.from(value).toString('base64')]; const source = 'before ' + variants.join(' middle ') + ' after'; for (let size = 1; size <= source.length; size++) { let output = ''; const filter = outputFilter(value, text => { output += text; }); @@ -92,6 +92,55 @@ test('output filtering masks literal and encoded values across every chunk bound } }); +test('legacy bearer connections remain readable and changing auth settings retains the saved key', async t => { + const { directory, store } = await fixture(t); + await store.list(); + const file = path.join(directory, 'credentials.json'); + const legacy = JSON.stringify({ version: 1, profiles: [{ id: 'service', label: 'Service API', type: 'api', baseUrl: 'https://api.example.com/v1/', secret }] }); + await fs.writeFile(file, legacy, { mode: 0o600 }); + assert.equal((await store.forUse('service')).authType, 'bearer'); + assert.equal(await fs.readFile(file, 'utf8'), legacy); + const before = await store.list(); + const saved = await store.save({ profile: { ...before.profiles[0], authType: 'header', authName: 'X-API-Key', authPrefix: '', testPath: 'account', secret: '' }, revision: before.revision }); + assert.equal(JSON.stringify(saved).includes(secret), false); + assert.equal((await store.forUse('service')).secret, secret); + assert.equal((await store.list()).profiles[0].authName, 'X-API-Key'); +}); + +test('API authentication and test-path validation rejects unsafe configuration', async t => { + const { store } = await fixture(t); + const profile = { id: 'service', label: 'Service API', type: 'api', baseUrl: 'https://api.example.com/v1/', secret }; + for (const change of [{ authType: 'unknown' }, { authType: 'header', authName: 'bad:name' }, { authType: 'header', authName: 'Host' }, + { authType: 'header', authName: 'Content-Length' }, { authType: 'header', authName: 'X-Key', authPrefix: 'Token\r\ninjected' }, + { authType: 'query', authName: 'key\ninjected' }, { testPath: '/outside' }, { testPath: '../outside' }, { testPath: 'https://other.test/' }]) { + await assert.rejects(create(store, { ...profile, ...change }), error => error.status === 400 && !error.message.includes(secret)); + } +}); + +for (const [authType, authName, authPrefix] of [['bearer', undefined, undefined], ['header', 'X-API-Key', ''], ['header', 'Authorization', 'Token'], ['query', 'api_key', undefined], ['query', 'api[key]', undefined]]) { + test(`API ${authType} ${authName || ''} ${authPrefix || ''} authentication uses the saved key and configured test path`, async t => { + const { store } = await fixture(t); let received; + const key = authType === 'query' ? secret + '/+ ~' : secret; + const server = createServer((req, res) => { + const url = new URL(req.url, 'http://localhost'); received = { headers: req.headers, url }; + res.end(JSON.stringify({ echo: authType === 'query' ? url.search : req.headers[(authName || 'authorization').toLowerCase()] })); + }); + server.listen(0, '127.0.0.1'); await once(server, 'listening'); + t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); + await create(store, { id: 'service', label: 'Service API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/v1/', secret: key, + authType, authName, authPrefix, testPath: 'account' }); + const profile = await store.forUse('service'); + assert.equal(await testCredential(profile), 0); + assert.equal(received.url.pathname, '/v1/account'); + if (authType === 'query') { assert.equal(received.url.searchParams.get(authName), key); assert.equal(received.headers.authorization, undefined); } + else assert.equal(received.headers[(authName || 'authorization').toLowerCase()], (authType === 'bearer' ? 'Bearer ' : authPrefix ? authPrefix + ' ' : '') + key); + let output = ''; + assert.equal(await apiRequest(profile, 'GET', 'projects?limit=2', { stdout: { write: value => { output += value; } } }), 0); + assert.equal(received.url.searchParams.get('limit'), '2'); + assert.equal(output.includes(secret), false); assert.match(output, /\[redacted\]/); + }); +} + test('API helper authenticates internally, filters output and never follows redirects', async t => { let calls = 0, received; const server = createServer(async (req, res) => { @@ -104,11 +153,11 @@ test('API helper authenticates internally, filters output and never follows redi }); server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); - const profile = { id: 'ha', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret }; + const profile = { id: 'project-api', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret }; let output = ''; - assert.equal(await apiRequest(profile, 'POST', 'services/light/turn_on', { body: '{"entity_id":"light.kitchen"}', stdout: { write: text => { output += text; } } }), 0); + assert.equal(await apiRequest(profile, 'POST', 'projects', { body: '{"name":"demo-project"}', stdout: { write: text => { output += text; } } }), 0); assert.equal(output, 'hello [redacted] goodbye'); - assert.deepEqual(received, { url: '/api/services/light/turn_on', method: 'POST', body: '{"entity_id":"light.kitchen"}' }); + assert.deepEqual(received, { url: '/api/projects', method: 'POST', body: '{"name":"demo-project"}' }); await assert.rejects(apiRequest(profile, 'GET', 'redirect'), /redirects are not followed/); assert.equal(calls, 2, 'redirect destination was never requested'); await assert.rejects(apiRequest(profile, 'GET', 'unauthorized', { probe: true }), error => !error.message.includes(secret) && /HTTP 401/.test(error.message)); From 15d4f0932a459f258649a32ef35afbb35d06984a Mon Sep 17 00:00:00 2001 From: 0libote <79215282+0libote@users.noreply.github.com> Date: Tue, 27 Oct 2026 09:33:50 +0000 Subject: [PATCH 5/8] fix: accept IPv6 hosts and report API status without secrets Allow valid IPv6 addresses such as ::1 in SSH hosts. Report HTTP status on stderr for helper API failures while keeping secrets filtered from output. Add regression tests for both. --- docker/setup/credentials.mjs | 3 ++- docker/setup/credentials/run.mjs | 7 +++++-- tests/credentials.test.mjs | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docker/setup/credentials.mjs b/docker/setup/credentials.mjs index aff52c32..446042a3 100644 --- a/docker/setup/credentials.mjs +++ b/docker/setup/credentials.mjs @@ -3,6 +3,7 @@ import * as fs from 'node:fs/promises'; import { constants } from 'node:fs'; import path from 'node:path'; +import { isIP } from 'node:net'; import { createHash, randomUUID } from 'node:crypto'; export class CredentialError extends Error { @@ -32,7 +33,7 @@ function normalize(input, previous) { if (!text(secret, 8192)) fail('Enter a password or API key of up to 8192 characters, without line breaks.'); const profile = { id: input.id, label: input.label.trim(), type: input.type, secret }; if (input.type === 'ssh') { - if (!text(input.host, 253) || !/^[a-zA-Z0-9][a-zA-Z0-9.:-]*$/.test(input.host)) fail('Enter a hostname or IP address, without a username or port.'); + if (!text(input.host, 253) || !(isIP(input.host) || /^[a-zA-Z0-9][a-zA-Z0-9.-]*$/.test(input.host))) fail('Enter a hostname or IP address, without a username or port.'); if (!text(input.username, 64) || !/^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(input.username)) fail('Enter a valid SSH username.'); if (!Number.isInteger(input.port) || input.port < 1 || input.port > 65535) fail('Enter an SSH port from 1 to 65535.'); Object.assign(profile, { host: input.host, username: input.username, port: input.port }); diff --git a/docker/setup/credentials/run.mjs b/docker/setup/credentials/run.mjs index 394afb47..a7c8a324 100644 --- a/docker/setup/credentials/run.mjs +++ b/docker/setup/credentials/run.mjs @@ -53,7 +53,7 @@ export async function sshRequest(profile, command, { stdout = process.stdout, st return code; } -export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, probe = false, signal = AbortSignal.timeout(30000) } = {}) { +export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, stderr = process.stderr, probe = false, signal = AbortSignal.timeout(30000) } = {}) { if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new CredentialError('Use GET, HEAD, POST, PUT, PATCH or DELETE.'); const target = apiTarget(profile, relative); try { @@ -66,7 +66,10 @@ export async function apiRequest(profile, method, relative, { body, stdout = pro if (probe) { await response.body?.cancel(); if (!response.ok) throw new CredentialError('The API did not accept the request (HTTP ' + response.status + '). Check the address and authentication settings.', 502); - } else if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); + } else { + if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); + if (!response.ok) stderr.write('HTTP ' + response.status + '\n'); + } return response.ok ? 0 : 1; } catch (error) { if (error instanceof CredentialError) throw error; diff --git a/tests/credentials.test.mjs b/tests/credentials.test.mjs index 6aa34bda..2227e379 100644 --- a/tests/credentials.test.mjs +++ b/tests/credentials.test.mjs @@ -198,3 +198,23 @@ setTimeout(()=>{process.stdout.write(secret.slice(5)+' done');process.stderr.wri if (interrupted.signalCode === null && interrupted.exitCode === null) await once(interrupted, 'close'); assert.equal(interrupted.signalCode, 'SIGTERM'); }); + +test('SSH hosts accept IPv6 addresses including leading ::', async t => { + const { store } = await fixture(t); + for (const host of ['::1', '::', '2001:db8::1']) { + await create(store, { ...ssh, id: 'v6-' + host.length, host }); + } + await assert.rejects(create(store, { ...ssh, id: 'bad-host', host: '-oProxyCommand=bad' })); +}); + +test('API helper reports HTTP status on stderr for non-probe failures without the secret', async t => { + const server = createServer((req, res) => { res.writeHead(401); res.end(secret); }); + server.listen(0, '127.0.0.1'); await once(server, 'listening'); + t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); + const profile = { id: 'project-api', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret }; + let output = '', error = ''; + assert.equal(await apiRequest(profile, 'GET', 'projects', { stdout: { write: value => { output += value; } }, stderr: { write: value => { error += value; } } }), 1); + assert.equal(output, '[redacted]'); + assert.match(error, /HTTP 401/); + assert.equal((output + error).includes(secret), false); +}); From f80a345bc7bdde0903ce1b704891988ec7ee9091 Mon Sep 17 00:00:00 2001 From: Ziyang Zeng Date: Sat, 31 Oct 2026 03:07:58 +0000 Subject: [PATCH 6/8] feat(credentials): add versioned logins and explicit host trust --- CONTRIBUTING.md | 2 +- README.md | 2 +- docker/setup/app.js | 4 +- docker/setup/client/credentials.js | 10 +- docker/setup/client/model.js | 28 +- docker/setup/client/routes.js | 5 +- docker/setup/credentials.mjs | 307 ++++++++++-------- docker/setup/credentials/cli.mjs | 4 +- docker/setup/credentials/diagnostics.mjs | 41 +++ docker/setup/credentials/errors.mjs | 11 + docker/setup/credentials/hostkeys.mjs | 92 ++++++ docker/setup/credentials/io.mjs | 94 ++++++ docker/setup/credentials/model.mjs | 52 +++ docker/setup/credentials/redact.mjs | 21 ++ docker/setup/credentials/run.mjs | 129 ++++---- docker/setup/credentials/service.mjs | 95 ++++++ docker/setup/credentials/state.mjs | 38 +++ docker/setup/credentials/usage.mjs | 60 ++++ docker/setup/server.mjs | 42 ++- .../{server-credentials.md => credentials.md} | 0 scripts/credentials-smoke.mjs | 8 +- tests/console-model.test.mjs | 11 + tests/credentials-api.test.mjs | 24 +- tests/credentials-service.test.mjs | 152 +++++++++ tests/credentials-store.test.mjs | 162 +++++++++ tests/credentials-usage.test.mjs | 35 ++ tests/credentials.test.mjs | 60 ++-- tests/fixtures/credential-keys.mjs | 7 + 28 files changed, 1224 insertions(+), 272 deletions(-) create mode 100644 docker/setup/credentials/diagnostics.mjs create mode 100644 docker/setup/credentials/errors.mjs create mode 100644 docker/setup/credentials/hostkeys.mjs create mode 100644 docker/setup/credentials/io.mjs create mode 100644 docker/setup/credentials/model.mjs create mode 100644 docker/setup/credentials/redact.mjs create mode 100644 docker/setup/credentials/service.mjs create mode 100644 docker/setup/credentials/state.mjs create mode 100644 docker/setup/credentials/usage.mjs rename docs/{server-credentials.md => credentials.md} (100%) create mode 100644 tests/credentials-service.test.mjs create mode 100644 tests/credentials-store.test.mjs create mode 100644 tests/credentials-usage.test.mjs create mode 100644 tests/fixtures/credential-keys.mjs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 82f212e0..f7302804 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,7 +144,7 @@ and Chromium; set `CHROME_PATH` if needed. Screenshots go to `/tmp/t3-opencode-auth-ui` (`T3_AUTH_UI_OUTPUT` overrides it). These audits never read or change your real OpenCode credentials. -For Server credentials changes, run `node --test tests/credentials*.test.mjs` +For Credentials changes, run `node --test tests/credentials*.test.mjs` and `node scripts/credentials-ui-audit.mjs`. The UI audit uses a real setup server in a disposable home, synthetic credentials and intercepted connection tests. It covers add/edit/delete, masked values, failed reads, concurrent edits diff --git a/README.md b/README.md index f6532a27..0b6f7bcb 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ instead. Details: [Reaching the server from a phone](docs/remote-access.md). | [Upgrading T3 Code](docs/t3code-updates.md) | Stable and Nightly, auto-update, rollback | | [Toolchains](docs/toolchains.md) | Go, Rust and friends, any mise tool, per-project versions | | [Source control](docs/source-control.md) | gh, glab, fj, tea and az sign-in | -| [Server credentials](docs/server-credentials.md) | Saved SSH passwords and API keys, used by name without putting values in chat | +| [Credentials](docs/credentials.md) | Saved SSH passwords and API keys, used by name without putting values in chat | | [Publishing a port](docs/ports.md) | Public URLs for dev servers | | [Giving agents a browser](docs/agent-browser.md) | T3's server browser and the browser MCP servers | | [Context management](docs/context-management.md) | Global `AGENTS.md` and the shared skill library | diff --git a/docker/setup/app.js b/docker/setup/app.js index dd7564de..618bcb84 100644 --- a/docker/setup/app.js +++ b/docker/setup/app.js @@ -868,8 +868,8 @@ `; /** The page a "Needs you" item lives on, and that page's link when they all share one. */ - const NEEDS_PAGES = { agents: 'All agents', toolchains: 'All toolchains', sourcecontrol: 'Source control', ports: 'All ports', server: 'Server', storage: 'Storage', updates: 'Updates' }; - const needsPage = (x) => x.target === 'port' ? 'ports' : x.target === 'harness' ? 'agents' + const NEEDS_PAGES = { agents: 'All agents', toolchains: 'All toolchains', sourcecontrol: 'Source control', ports: 'All ports', server: 'Server', storage: 'Storage', updates: 'Updates', credentials: 'Credentials' }; + const needsPage = (x) => x.target === 'credential' ? 'credentials' : x.target === 'port' ? 'ports' : x.target === 'harness' ? 'agents' : x.target === 'server' ? (x.action && x.action.route) || 'server' : x.target === 'toolchain' && M.SOURCE_CONTROL[x.id] ? 'sourcecontrol' : 'toolchains'; diff --git a/docker/setup/client/credentials.js b/docker/setup/client/credentials.js index d5546114..de53a9f3 100644 --- a/docker/setup/client/credentials.js +++ b/docker/setup/client/credentials.js @@ -18,7 +18,7 @@ const T3CredentialsUI = (() => { started = true; loading = true; error = null; paint(); const response = await api('/credentials'); if (version !== epoch) return; - if (response.ok && Array.isArray(response.data?.profiles)) data = response.data; + if (response.ok && Array.isArray(response.data?.credentials)) data = { ...response.data, profiles: response.data.credentials.map(row => ({ ...row, label: row.id })) }; else error = response.error || 'Could not load saved connections.'; loading = false; paint(); }; @@ -37,7 +37,7 @@ const T3CredentialsUI = (() => { const openEditor = profile => { if (editor || !data || error || loading) return; notice?.close(); notice = null; - const view = { original: profile, revision: data.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '', authType: 'bearer', authName: 'X-API-Key', authPrefix: '', testPath: '' }, busy: false, error: null }; + const view = { original: profile, revision: profile?.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '', authType: 'bearer', authName: 'X-API-Key', authPrefix: '', testPath: '' }, busy: false, error: null }; editor = view; const field = (key, label, options = {}) => html`
${options.hint ? html`

${options.hint}

` : ''}
`; const markup = () => html`
@@ -74,7 +74,7 @@ const T3CredentialsUI = (() => { const secretInput = view.layer.panel.querySelector('#credential-secret'); const payload = { ...view.draft, port: Number(view.draft.port), secret: secretInput.value || undefined }; view.busy = true; view.error = null; view.layer.render(); - const response = await api(profile ? '/credentials/save' : '/credentials/create', { body: { profile: payload, revision: view.revision } }); + const response = await api(profile ? '/credentials/save' : '/credentials/create', { body: { credential: payload, revision: view.revision } }); delete payload.secret; if (response.ok) { secretInput.value = ''; results.delete(view.draft.id); @@ -95,7 +95,7 @@ const T3CredentialsUI = (() => { if (action === 'copy' && profile) { void Kit.copy(command(profile), button, 'Skill command copied'); return; } if (!profile || busy.has(profile.id) || error) return; if (action === 'edit') { openEditor(profile); return; } - const revision = data.revision; + const revision = profile.revision; if (action === 'remove') { const yes = await Kit.confirm({ title: 'Delete ' + profile.label + '?', body: 'Removes the saved login. Skills using ' + profile.id + ' will need another connection.', confirm: 'Delete connection', tone: 'danger' }); if (!yes || busy.has(profile.id)) return; @@ -103,7 +103,7 @@ const T3CredentialsUI = (() => { busy.add(profile.id); results.delete(profile.id); paint(); const response = await api('/credentials/' + action, { body: { id: profile.id, revision } }); busy.delete(profile.id); - if (action === 'test') results.set(profile.id, { ok: response.ok, message: response.ok ? 'Connection succeeded' : response.error }); + if (action === 'test') results.set(profile.id, { ok: response.ok && response.data?.result?.ok, message: response.ok ? response.data?.result?.code === 'ok' ? 'Connection succeeded' : 'Connection needs attention: ' + response.data?.result?.code : response.error }); else if (response.ok) notify('Connection deleted'); else notify('Could not delete connection', { tone: 'danger', detail: response.error }); await load(); diff --git a/docker/setup/client/model.js b/docker/setup/client/model.js index 81f7791a..ebf72c56 100644 --- a/docker/setup/client/model.js +++ b/docker/setup/client/model.js @@ -1344,10 +1344,35 @@ const T3Model = (() => { action: { cmd: 'port.publish', id: String(p.port), label: 'Retry', icon: 'refresh-cw' } }); } } + for (const item of s.credentials?.attention || []) { + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(item.id || '') || item.id.length > 64) continue; + const warn = item.code === 'host-key-untrusted' || item.code === 'host-key-changed'; + items.push({ target: 'credential', id: item.id, key: 'credential:' + item.id, icon: 'key-round', tone: warn ? 'warn' : 'danger', severity: warn ? 1 : 0, + name: item.id, text: credentialProblem(item.code), action: { cmd: 'goto', route: 'credentials/' + item.id, label: 'Review' } }); + } // Stable within a severity: the order each page lists them in. return items.map((item, i) => [item, i]).sort((a, b) => a[0].severity - b[0].severity || a[1] - b[1]).map(([item]) => item); }; + // Credential copy is shared by list, sheets and Overview attention. + const CREDENTIAL_RESULTS = {"ssh":{"ok":{"tone":"ok","row":["Connected","{when}"],"sheet":{"title":"Connected {when}","desc":"Signed in as {user}. The host key matched."},"action":"Test"},"auth-rejected":{"tone":"danger","row":["Password rejected","{when}"],"sheet":{"title":"Password rejected","desc":"{host} didn’t accept the saved password for {user}. Replace it if it changed."},"action":"Replace…"},"unreachable":{"tone":"danger","row":["Unreachable","{when}"],"sheet":{"title":"Couldn’t reach {host}","desc":"Nothing answered on port {port}. Check the address, and that the server is on and allows SSH from here."},"action":"Test"},"timeout":{"tone":"danger","row":["Timed out","{when}"],"sheet":{"title":"Timed out","desc":"{host} didn’t finish signing in within 15 seconds."},"action":"Test"},"host-key-untrusted":{"tone":"warn","row":["Host key not trusted yet","Agents can’t connect yet"],"sheet":{"title":"Host key not trusted yet","desc":"Compare {host}’s key with the server’s own, then trust it. Nothing signs in until you do."},"action":"Review…"},"host-key-changed":{"tone":"warn","row":["Host key changed","Blocked until you review it"],"sheet":{"title":"Host key changed","desc":"{host} presents a different key than the one you trusted. Agents can’t connect until you review it."},"action":"Review…"},"scan-failed":{"tone":"danger","row":["Couldn’t read the host key","{when}"],"sheet":{"title":"Couldn’t read {host}’s host key","desc":"It answered on port {port} but didn’t offer an ed25519, ECDSA or RSA key."},"action":"Test"},"failed":{"tone":"danger","row":["Failed","{when}"],"sheet":{"title":"Couldn’t sign in","desc":"SSH said: {line}"},"action":"Test"}},"api":{"ok":{"tone":"ok","row":["Connected · HTTP {status}","{when}"],"sheet":{"title":"Connected {when}","desc":"GET {path} answered HTTP {status} in {ms} ms."},"action":"Test"},"rejected":{"tone":"danger","row":["Rejected · HTTP {status}","{when}"],"sheet":{"title":"Rejected · HTTP {status}","desc":"Tested {when}. The service didn’t accept the saved {secretKind}. Replace it if it was revoked or expired."},"action":"Replace…"},"not-found":{"tone":"danger","row":["Test path not found · HTTP 404","{when}"],"sheet":{"title":"Test path not found","desc":"GET {path} answered HTTP 404. Check the test path and the base URL’s version."},"action":"Edit…"},"http-error":{"tone":"danger","row":["HTTP {status}","{when}"],"sheet":{"title":"The service answered HTTP {status}","desc":"GET {path} didn’t succeed. A test path must be an endpoint that accepts GET."},"action":"Test"},"redirect":{"tone":"danger","row":["Redirected","{when}"],"sheet":{"title":"The service redirected the request","desc":"Requests never follow redirects, so the key isn’t sent elsewhere. Use the address it redirects to as the base URL."},"action":"Edit…"},"certificate":{"tone":"danger","row":["Certificate not trusted","{when}"],"sheet":{"title":"Certificate not trusted","desc":"{host}’s HTTPS certificate didn’t verify, so the key wasn’t sent."},"action":"Test"},"unreachable":{"tone":"danger","row":["Unreachable","{when}"],"sheet":{"title":"Couldn’t reach {host}","desc":"The address didn’t resolve or didn’t answer. Check it, and this server’s network."},"action":"Test"},"timeout":{"tone":"danger","row":["Timed out","{when}"],"sheet":{"title":"Timed out","desc":"{host} didn’t answer within 15 seconds."},"action":"Test"}},"untested":{"tone":"muted","attention":false,"row":["Not tested yet",""],"sheet":{"title":"Not tested yet","desc":"Test it once to know agents can use it."},"action":"Test"},"testing":{"tone":"muted","row":["Testing…",""],"sheet":{"title":"Testing…","desc":""}}}; + const credentialState = (profile, { busy = false, now = Date.now() } = {}) => { + const result = profile.test, code = busy ? 'testing' : profile.type === 'ssh' && !profile.hostKey ? 'host-key-untrusted' : result?.code || 'untested'; + const source = CREDENTIAL_RESULTS[code] || CREDENTIAL_RESULTS[profile.type]?.[code] || CREDENTIAL_RESULTS.untested; + let host = profile.host || profile.baseUrl || ''; + if (profile.type === 'api') { try { host = new URL(profile.baseUrl).host; } catch {} } + const values = { id: profile.id, host, port: profile.port, status: result?.detail?.status, user: profile.username || result?.detail?.user, + when: result?.at ? relTime(result.at, now) : '', ms: result?.ms || 0, line: result?.detail?.line || 'The connection did not complete.', + path: profile.testPath || 'the base URL', secretKind: profile.authType === 'bearer' ? 'token' : profile.type === 'ssh' ? 'password' : 'key' }; + const fill = text => String(text || '').replace(/\{(\w+)\}/g, (_, name) => values[name] ?? ''); + return { code, tone: source.tone, label: fill(source.row[0]), sub: fill(source.row[1]), title: fill(source.sheet.title), desc: fill(source.sheet.desc), + action: source.action || 'Test', at: result?.at || null, icon: busy ? null : source.tone === 'ok' ? 'circle-check' : source.tone === 'warn' ? 'triangle-alert' : source.tone === 'danger' ? 'circle-x' : 'circle-help' }; + }; + const credentialProblem = code => { + const text = CREDENTIAL_RESULTS.ssh[code]?.row[0] || CREDENTIAL_RESULTS.api[code]?.row[0] || 'Connection needs attention'; + return code === 'http-error' ? 'The API request failed' : text.split(' · HTTP')[0]; + }; + // ------------------------------------------------------------- activity -- /** Work running now, queued behind it, and what finished recently. */ const activity = (status, ui, now) => { @@ -1449,6 +1474,7 @@ const T3Model = (() => { access: warn(!s.publicUrl && s.server && connectView(s).state !== 'on' && connectView(s).state !== 'linking' ? 1 : 0), agents: warn(agents.filter((a) => a.attention).length) || running(busy(agents)), instructions: null, + credentials: warn(s.credentials?.attention?.length || 0), mcp: warn((s.context?.mcp?.providers || []).filter(p => p.supported && s.harnesses?.some(a => a.id === p.provider && a.installed)).reduce((n, p) => n + (p.diverged?.length || 0) + (p.error ? 1 : 0), 0)), toolchains: warn(tools.filter((t) => t.state === 'failed').length) || running(busy(tools)), // A source control CLI someone installed and has not signed in is as @@ -2025,7 +2051,7 @@ const T3Model = (() => { agentRow, agentRows, toolRow, toolchainRow, toolchainRows, sourceControlRows, managedSourceControlRows, packageRows, portRows, looksLikeDatabase, monogram, managedOn, isVersionSpec, isToolSpec, specPrefix, SPEC_SAMPLES, searchRegistry, resolveRelease, matchReleases, releaseIndex, heldRelease, versionOf, toolName, SUGGESTED_TOOLS, deviceRows, linkRows, deviceKind, deviceName, - readiness, readySummary, needsYou, containerItems, activity, setupBanner, setupFailures, + credentialState, credentialProblem, readiness, readySummary, needsYou, containerItems, activity, setupBanner, setupFailures, publicUrlSource, hereOffer, connectView, contextView, contextAgentsMdRow, contextProviderRows, mcpView, diff --git a/docker/setup/client/routes.js b/docker/setup/client/routes.js index 20ccc37a..94bfcce2 100644 --- a/docker/setup/client/routes.js +++ b/docker/setup/client/routes.js @@ -30,11 +30,12 @@ const T3Routes = (() => { { route: 'mcp', title: 'MCP servers', icon: 'plug', key: 'm', group: 'agents', summary: 'Servers your agents can start or connect to.', doc: 'mcp-servers.md', palette: { meta: 'Setup · shared definitions and provider configuration', terms: ['mcp tools servers'] } }, + { route: 'credentials', title: 'Credentials', icon: 'key-round', key: 'c', group: 'agents', + summary: 'Saved logins your skills can use, without putting passwords or keys in chat.', doc: 'credentials.md', palette: { meta: 'Setup · SSH and API logins agents use by name', terms: ['ssh', 'api key', 'token', 'password', 'secret', 'server credentials'] } }, { route: 'files', title: 'Files', icon: 'folder', key: 'f', group: 'tools', summary: 'Your projects, your home folder and what fills the disk.', doc: 'files.md', palette: { meta: 'Setup · projects, the home folder and disk use', terms: ['upload download', 'workspace'] } }, - { route: 'credentials', title: 'Server credentials', icon: 'key-round', key: 'c', group: 'tools', - summary: 'SSH passwords and API keys your agents can use by name.', doc: 'server-credentials.md' }, + { route: 'toolchains', title: 'Toolchains', icon: 'wrench', key: 't', group: 'tools', summary: 'Languages and tools on every agent’s path, at exact versions.', doc: 'toolchains.md', palette: { meta: 'Setup · Go, Rust, Bun, Deno, uv and any mise tool' } }, diff --git a/docker/setup/credentials.mjs b/docker/setup/credentials.mjs index 446042a3..978a859f 100644 --- a/docker/setup/credentials.mjs +++ b/docker/setup/credentials.mjs @@ -1,153 +1,192 @@ -// Public reads return connection details only. Helpers read secrets directly, -// so saved passwords and tokens never need to pass through an agent prompt. -import * as fs from 'node:fs/promises'; -import { constants } from 'node:fs'; +// Secrets stay in an owner-only store. Revisions are random, independent tokens; +// testing and trust metadata never change a credential's revision. import path from 'node:path'; -import { isIP } from 'node:net'; -import { createHash, randomUUID } from 'node:crypto'; +import { randomBytes } from 'node:crypto'; +import { createCredentialIO } from './credentials/io.mjs'; +import { createCredentialState, emptyState, cleanResult } from './credentials/state.mjs'; +import { createHostKeys, publicKey, keyFile } from './credentials/hostkeys.mjs'; +import { normalize } from './credentials/model.mjs'; +import { CredentialError, validId, object } from './credentials/errors.mjs'; +export { CredentialError, credentialFailure } from './credentials/errors.mjs'; +export { apiTarget } from './credentials/model.mjs'; -export class CredentialError extends Error { - constructor(message, status = 400) { super(message); this.status = status; } -} -const fail = (message, status) => { throw new CredentialError(message, status); }; -const MAX_BYTES = 512 * 1024; -const object = value => value && typeof value === 'object' && !Array.isArray(value); -const text = (value, max) => typeof value === 'string' && value.isWellFormed() && value.length > 0 && value.length <= max && !/[\x00-\x1f\x7f]/.test(value); export const credentialDirectory = (env = process.env) => path.join(env.T3CODE_HOME || path.join(env.HOME || '/home/t3', '.t3'), 'server-credentials'); +const revision = () => randomBytes(8).toString('hex'); +const stamp = value => typeof value === 'string' && value.length < 40 && Number.isFinite(Date.parse(value)); +const serialize = profiles => JSON.stringify({ version: 2, profiles }, null, 2) + '\n'; +const unreadable = () => new CredentialError('Saved credentials could not be read. Restore the credential file before making changes.', 500, 'store'); +const requireId = id => { if (!validId(id)) throw new CredentialError('Choose a valid credential name.'); }; -export function apiTarget(profile, relative) { - if (profile.type !== 'api') throw new CredentialError('Choose an API connection.'); - if (typeof relative !== 'string' || relative.length > 2048 || !relative.isWellFormed() || /[\x00-\x1f\x7f]/.test(relative) || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) throw new CredentialError('Use a path relative to the saved API address, such as projects/123.'); - const base = new URL(profile.baseUrl), target = new URL(relative || '.', base); - if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.username || target.password || target.hash) throw new CredentialError('The request must stay inside the saved API address.'); - return target; -} - -function normalize(input, previous) { - if (!object(input)) fail('Enter connection details.'); - if (!text(input.id, 64) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.id)) fail('Use up to 64 lowercase letters, numbers and single hyphens for the connection ID.'); - if (!text(input.label, 120) || !input.label.trim()) fail('Enter a connection name of up to 120 characters.'); - if (!['ssh', 'api'].includes(input.type)) fail('Choose SSH password or API key / token.'); - if (previous && previous.type !== input.type) fail('Create a new connection to change its type.'); - const secret = input.secret === undefined || input.secret === '' ? previous?.secret : input.secret; - if (!text(secret, 8192)) fail('Enter a password or API key of up to 8192 characters, without line breaks.'); - const profile = { id: input.id, label: input.label.trim(), type: input.type, secret }; - if (input.type === 'ssh') { - if (!text(input.host, 253) || !(isIP(input.host) || /^[a-zA-Z0-9][a-zA-Z0-9.-]*$/.test(input.host))) fail('Enter a hostname or IP address, without a username or port.'); - if (!text(input.username, 64) || !/^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(input.username)) fail('Enter a valid SSH username.'); - if (!Number.isInteger(input.port) || input.port < 1 || input.port > 65535) fail('Enter an SSH port from 1 to 65535.'); - Object.assign(profile, { host: input.host, username: input.username, port: input.port }); - } else { - let url; - try { url = new URL(input.baseUrl); } catch { fail('Enter a complete http:// or https:// API address.'); } - if (!text(input.baseUrl, 2048) || !['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) fail('Use an HTTP or HTTPS API address without credentials, a query or a fragment.'); - if (!url.pathname.endsWith('/')) url.pathname += '/'; - profile.baseUrl = url.href; - profile.authType = input.authType ?? previous?.authType ?? 'bearer'; - if (!['bearer', 'header', 'query'].includes(profile.authType)) fail('Choose bearer token, custom header or query parameter authentication.'); - if (profile.authType !== 'bearer') { - const name = input.authName ?? previous?.authName; - if (!text(name, 128)) fail('Enter an authentication header or parameter name of up to 128 characters.'); - if (profile.authType === 'header') { - try { new Headers({ [name]: 'placeholder' }); } catch { fail('Enter a valid HTTP header name.'); } - if (['host', 'content-length', 'transfer-encoding', 'connection', 'upgrade', 'expect', 'trailer', 'te', 'accept', 'content-type'].includes(name.toLowerCase())) fail('Choose an authentication header, not a request transport or content header.'); - const prefix = input.authPrefix ?? previous?.authPrefix ?? ''; - if (typeof prefix !== 'string' || prefix.length > 128 || /[^\x20-\x7e]/.test(prefix)) fail('Use up to 128 printable ASCII characters for the optional header prefix.'); - profile.authPrefix = prefix.trim(); +export function createCredentialStore({ directory = credentialDirectory(), readOnly = false, home = process.env.HOME || '/home/t3', io = createCredentialIO({ directory, readOnly }), hostKeys = createHostKeys({ io, home }), clock = Date.now } = {}) { + const state = createCredentialState({ io }); + const now = () => new Date(clock()).toISOString(); + const commit = async (data, profiles, metadata, keys = new Map(), writeStore = true) => { + if (io.readOnly) throw new CredentialError('Helpers cannot change saved credentials.', 500, 'read-only'); + // In-memory recovery only: never make another plaintext credential backup. + const previousState = await io.read('state.json').catch(() => null); + const previousKeys = new Map(); + for (const id of keys.keys()) previousKeys.set(id, await io.read(keyFile(id), { maxBytes: 64 * 1024 }).catch(() => null)); + let attemptedStore = false; + try { + for (const [id, key] of keys) { if (key) await hostKeys.write(id, key); else await hostKeys.forget(id); } + await state.write(metadata); + if (writeStore) { attemptedStore = true; await io.write('credentials.json', serialize(profiles)); } + } catch (error) { + let restored = true; + if (attemptedStore) { + try { if (data.raw === null) await io.remove('credentials.json'); else await io.write('credentials.json', data.raw); } + catch { + try { const current = await io.read('credentials.json'); restored = (current?.text ?? null) === data.raw; } + catch { restored = false; } + } + } + if (restored) { + try { + for (const [id, key] of previousKeys) { if (key) await io.write(keyFile(id), key.text, { maxBytes: 64 * 1024, recover: true }); else await hostKeys.forget(id); } + if (previousState) await io.write('state.json', previousState.text, { recover: true }); else await io.remove('state.json'); + } catch { restored = false; } + } + if (!restored) { + // A failed rollback must block SSH rather than silently trusting a key. + for (const id of keys.keys()) await hostKeys.forget(id).catch(() => {}); + throw new CredentialError('The credential change could not be recovered. Check the state volume before trying again.', 500, 'store'); } - profile.authName = name; + throw error; } - profile.testPath = input.testPath ?? previous?.testPath ?? ''; - apiTarget(profile, profile.testPath); - } - return profile; -} - -const publicProfile = ({ secret, ...profile }) => ({ ...profile, hasSecret: true }); -const revisionOf = text => createHash('sha256').update(text).digest('hex'); -const EMPTY = JSON.stringify({ version: 1, profiles: [] }); -export const credentialFailure = error => error instanceof CredentialError - ? { status: error.status, body: { ok: false, error: error.message } } - : { status: 500, body: { ok: false, error: 'Could not access saved credentials. Check the state volume and its permissions.' } }; - -export function createCredentialStore({ directory = credentialDirectory() } = {}) { - const file = path.join(directory, 'credentials.json'); - let queue = Promise.resolve(); - const serial = action => { - const result = queue.then(action); - queue = result.catch(() => {}); - return result; }; - const secureDirectory = async () => { - await fs.mkdir(directory, { recursive: true, mode: 0o700 }); - const stat = await fs.lstat(directory); - if (!stat.isDirectory() || stat.uid !== process.getuid()) fail('The credential directory must belong to the container user and must not be a symbolic link.', 500); - await fs.chmod(directory, 0o700); + const migrate = async (data, file) => { + if (io.readOnly) throw new CredentialError('Open Setup once to finish upgrading saved credentials.', 409, 'migration'); + const at = file.mtime, profiles = data.profiles.map(input => ({ ...normalize(input), createdAt: at, updatedAt: at, secretChangedAt: null, revision: revision() })); + const metadata = emptyState(), keys = new Map(); + for (const profile of profiles.filter(row => row.type === 'ssh')) { + let key; + key = await hostKeys.legacy(profile); + keys.set(profile.id, key || null); + if (key) metadata.hostKeys[profile.id] = hostKeys.metadata(key, true); + } + await commit({ raw: file.text }, profiles, metadata, keys); + return { profiles, raw: serialize(profiles) }; }; const read = async () => { - await secureDirectory(); - let handle, raw = EMPTY; - try { - handle = await fs.open(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); - const stat = await handle.stat(); - if (!stat.isFile() || stat.nlink !== 1 || stat.uid !== process.getuid() || stat.size > MAX_BYTES) fail('The credential file is unsafe or exceeds its size limit. Repair it before continuing.', 500); - await handle.chmod(0o600); - raw = await handle.readFile('utf8'); - } catch (error) { - if (error.code !== 'ENOENT') throw error; - } finally { await handle?.close(); } + const file = await io.read('credentials.json'); + if (!file) return { profiles: [], raw: null }; let data; try { - data = JSON.parse(raw); - if (data.version !== 1 || !Array.isArray(data.profiles) || data.profiles.length > 64) throw new Error(); - data.profiles = data.profiles.map(profile => normalize(profile)); - if (new Set(data.profiles.map(profile => profile.id)).size !== data.profiles.length) throw new Error(); - } catch { fail('Saved credentials could not be read. Restore the credential file before making changes.', 500); } - return { profiles: data.profiles, revision: revisionOf(raw) }; + data = JSON.parse(file.text); + if (!object(data) || ![1, 2].includes(data.version) || !Array.isArray(data.profiles) || data.profiles.length > 64) throw unreadable(); + if (new Set(data.profiles.map(profile => profile?.id)).size !== data.profiles.length) throw unreadable(); + if (data.version === 2) data.profiles = data.profiles.map(input => { + const profile = normalize(input); + if (![input.createdAt, input.updatedAt].every(stamp) || !(input.secretChangedAt === null || stamp(input.secretChangedAt)) || !/^[a-f0-9]{16}$/.test(input.revision || '')) throw unreadable(); + return { ...profile, createdAt: input.createdAt, updatedAt: input.updatedAt, secretChangedAt: input.secretChangedAt, revision: input.revision }; + }); + else data.profiles.forEach(input => normalize(input)); + } catch { throw unreadable(); } + if (data.version === 1) { + try { return await migrate(data, file); } + catch (error) { if (error.code === 'migration') throw error; throw unreadable(); } + } + return { profiles: data.profiles, raw: file.text }; }; - const write = async profiles => { - const raw = JSON.stringify({ version: 1, profiles }, null, 2) + '\n'; - if (Buffer.byteLength(raw) > MAX_BYTES) fail('Saved credentials exceed the 512 KiB limit.'); - const temporary = path.join(directory, '.' + randomUUID() + '.tmp'); - try { - const handle = await fs.open(temporary, 'wx', 0o600); - try { await handle.writeFile(raw); await handle.sync(); } finally { await handle.close(); } - await fs.rename(temporary, file); - } finally { await fs.rm(temporary, { force: true }); } - return revisionOf(raw); + const publicProfile = async (profile, metadata) => { + const { secret, ...visible } = profile; + let key = null; + if (profile.type === 'ssh') { try { key = await hostKeys.read(profile.id); } catch { /* Unsafe files cannot confer trust. */ } } + const saved = metadata.hostKeys[profile.id], test = metadata.tests[profile.id]; + return { ...visible, hasSecret: true, test: test && (!test.revision || test.revision === profile.revision) ? cleanResult(test, secret) : null, + hostKey: profile.type === 'ssh' && key ? { ...publicKey(key), trustedAt: saved?.fingerprint === key.fingerprint ? saved.trustedAt : key.trustedAt, carried: saved?.fingerprint === key.fingerprint && saved.carried === true } : null }; }; - const checkRevision = (expected, actual) => { - if (expected !== actual) fail('Connections changed in another window. Close this editor, reload the list and reopen the connection before saving again.', 409); + const current = async (data, id, expected) => { + requireId(id); + const profile = data.profiles.find(row => row.id === id); + if (!profile) throw new CredentialError('This credential was deleted in another window.', 409, 'gone'); + if (expected !== profile.revision) throw new CredentialError('This credential changed in another window.', 409, 'changed', { current: await publicProfile(profile, await state.read(data.profiles)) }); + return profile; }; - return { - async list() { - const data = await read(); - return { profiles: data.profiles.map(publicProfile), revision: data.revision }; - }, - save: ({ profile, revision, create = false }) => serial(async () => { - const data = await read(); - checkRevision(revision, data.revision); - const index = data.profiles.findIndex(row => row.id === profile?.id); - if (create && index >= 0) fail('This connection ID is already in use. Choose another ID.', 409); - if (!create && index < 0) fail('This connection no longer exists. Reload the list.', 409); - const saved = normalize(profile, data.profiles[index]); - if (index < 0) { - if (data.profiles.length >= 64) fail('Save at most 64 connections.'); - data.profiles.push(saved); - } else data.profiles[index] = saved; - return { profile: publicProfile(saved), revision: await write(data.profiles) }; + const privateProfile = (data, id) => { + requireId(id); + const profile = data.profiles.find(row => row.id === id); + if (!profile) throw new CredentialError('Saved credential not found. Add it in Setup → Credentials.', 404, 'not-found'); + return profile; + }; + const store = { + io, hostKeys, + initialize: () => io.transaction(async () => { await read(); }), + list: () => io.transaction(async () => { const data = await read(), metadata = await state.read(data.profiles); return { credentials: await Promise.all(data.profiles.map(profile => publicProfile(profile, metadata))) }; }), + public: id => io.transaction(async () => { const data = await read(); return publicProfile(privateProfile(data, id), await state.read(data.profiles)); }), + draft: ({ draft, id }) => io.transaction(async () => { + const data = await read(), previous = id === undefined ? undefined : privateProfile(data, id), profile = normalize(draft, previous); + if (profile.type === 'ssh' && previous && profile.host === previous.host && profile.port === previous.port) { + const key = await hostKeys.read(id).catch(() => null); + if (key) return { ...profile, knownHostsFile: key.file, hostKeyType: key.type }; + } + return profile; }), - remove: ({ id, revision }) => serial(async () => { + save: ({ credential, revision: expected, create = false }) => io.transaction(async () => { const data = await read(); - checkRevision(revision, data.revision); - if (!data.profiles.some(row => row.id === id)) fail('This connection no longer exists.', 404); - return { revision: await write(data.profiles.filter(row => row.id !== id)) }; + requireId(credential?.id); + const previous = data.profiles.find(row => row.id === credential.id); + if (create && previous) throw new CredentialError('That name is already taken. Choose another credential name.', 409, 'taken'); + if (!create) await current(data, credential.id, expected); + if (!previous && data.profiles.length >= 64) throw new CredentialError('Save at most 64 credentials.'); + const normalized = normalize(credential, previous), at = now(); + const saved = { ...normalized, createdAt: previous?.createdAt || at, updatedAt: at, secretChangedAt: !previous || normalized.secret !== previous.secret ? at : previous.secretChangedAt, revision: revision() }; + const metadata = await state.read(data.profiles), keys = new Map(); + const changed = !previous || JSON.stringify(normalize(previous)) !== JSON.stringify(normalized); + if (changed) delete metadata.tests[saved.id]; + else if (metadata.tests[saved.id]) metadata.tests[saved.id].revision = saved.revision; + if (saved.type === 'ssh' && (!previous || saved.host !== previous.host || saved.port !== previous.port)) { keys.set(saved.id, null); delete metadata.hostKeys[saved.id]; } + const profiles = [...data.profiles.filter(row => row.id !== saved.id), saved]; + await commit(data, profiles, metadata, keys); + return { credential: await publicProfile(saved, metadata) }; + }), + remove: ({ id, revision: expected }) => io.transaction(async () => { + const data = await read(), profile = await current(data, id, expected), metadata = await state.read(data.profiles); + delete metadata.tests[id]; delete metadata.hostKeys[id]; + await commit(data, data.profiles.filter(row => row.id !== id), metadata, profile.type === 'ssh' ? new Map([[id, null]]) : new Map()); + return {}; + }), + forUse: id => io.transaction(async () => { + const profile = privateProfile(await read(), id); + if (profile.type !== 'ssh') return profile; + let key = null; + try { key = await hostKeys.read(id); } catch { /* Helpers must stop at missing or unsafe trust. */ } + return { ...profile, knownHostsFile: key?.file || null, hostKeyType: key?.type || null, hostFingerprint: key?.fingerprint || null }; + }), + trust: ({ id, revision: expected, key }) => io.transaction(async () => { + const data = await read(), profile = await current(data, id, expected); + if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + const metadata = await state.read(data.profiles); + metadata.hostKeys[id] = hostKeys.metadata(key); delete metadata.tests[id]; + await commit(data, data.profiles, metadata, new Map([[id, key]]), false); + return publicProfile(profile, metadata); + }), + forget: id => io.transaction(async () => { + const data = await read(), profile = privateProfile(data, id); + if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + const metadata = await state.read(data.profiles); + delete metadata.hostKeys[id]; delete metadata.tests[id]; + await commit(data, data.profiles, metadata, new Map([[id, null]]), false); + return publicProfile(profile, metadata); + }), + recordTest: ({ id, revision: expected, hostFingerprint, result }) => io.transaction(async () => { + const data = await read(), profile = data.profiles.find(row => row.id === id); + if (!profile || profile.revision !== expected) return false; + if (profile.type === 'ssh') { const key = await hostKeys.read(id).catch(() => null); if ((key?.fingerprint || null) !== hostFingerprint) return false; } + const metadata = await state.read(data.profiles), previous = metadata.tests[id], cleaned = cleanResult(result, profile.secret); + if (!cleaned) throw new CredentialError('The connection test returned an invalid result.', 500); + metadata.tests[id] = { ...cleaned, at: now(), revision: expected, consecutiveTimeouts: result.code === 'timeout' ? (previous?.consecutiveTimeouts || 0) + 1 : 0 }; + await state.write(metadata); return true; + }), + summary: () => io.transaction(async () => { + const data = await read(), metadata = await state.read(data.profiles), credentials = await Promise.all(data.profiles.map(profile => publicProfile(profile, metadata))); + return { count: credentials.length, attention: credentials.flatMap(profile => { + let code = profile.test?.ok === false ? profile.test.code : null; + if (code === 'timeout' && (metadata.tests[profile.id]?.consecutiveTimeouts || 0) < 2) code = null; + if (profile.type === 'ssh' && !profile.hostKey) code = 'host-key-untrusted'; + return code ? [{ id: profile.id, code }] : []; + }) }; }), - async forUse(id) { - const data = await read(); - const profile = data.profiles.find(row => row.id === id); - if (!profile) fail('Saved connection not found. Add it in Setup → Server credentials.', 404); - return profile; - }, }; + return store; } diff --git a/docker/setup/credentials/cli.mjs b/docker/setup/credentials/cli.mjs index febb6fc2..0f57e4c7 100644 --- a/docker/setup/credentials/cli.mjs +++ b/docker/setup/credentials/cli.mjs @@ -5,7 +5,7 @@ const USAGE = `Use saved credentials without putting their values in commands: t3-ssh CONNECTION [--] COMMAND [ARGUMENT...] t3-api CONNECTION METHOD RELATIVE_PATH [--stdin] -Manage connections in Setup → Server credentials. +Manage connections in Setup → Credentials. For JSON request bodies, use --stdin and pipe the body into t3-api. Examples: t3-ssh build-server -- uptime @@ -16,7 +16,7 @@ Examples: async function main() { const [kind, ...args] = process.argv.slice(2); if (args.length === 0 || args[0] === '--help' || args[0] === '-h') { process.stdout.write(USAGE); return; } - const id = args.shift(), store = createCredentialStore(); + const id = args.shift(), store = createCredentialStore({ readOnly: true }); if (!['ssh', 'api'].includes(kind)) throw new CredentialError('Use t3-ssh or t3-api.'); if (kind === 'ssh') { if (args[0] === '--') args.shift(); diff --git a/docker/setup/credentials/diagnostics.mjs b/docker/setup/credentials/diagnostics.mjs new file mode 100644 index 00000000..97b14005 --- /dev/null +++ b/docker/setup/credentials/diagnostics.mjs @@ -0,0 +1,41 @@ +// OpenSSH closes inherited descriptors. A private FIFO separates its own +// diagnostics from a remote command's stderr without retaining a raw log. +import * as fs from 'node:fs/promises'; +import { constants } from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; +import { execute } from './hostkeys.mjs'; +import { outputFilter } from './redact.mjs'; + +export async function createSshDiagnostics(secret, write = () => {}) { + const directory = await fs.mkdtemp(path.join(os.tmpdir(), 't3-ssh-test-')); + const file = path.join(directory, 'diagnostics'); + let handle, ended = false, text = ''; + try { + await fs.chmod(directory, 0o700); + const answer = await execute('/usr/bin/mkfifo', ['-m', '600', '--', file]); + if (answer.code !== 0) throw new Error('Could not prepare SSH diagnostics'); + handle = await fs.open(file, constants.O_RDWR | constants.O_NONBLOCK); + const filter = outputFilter(secret, value => { text = (text + value).slice(-65536); write(value); }); + const reading = (async () => { + const buffer = Buffer.alloc(8192), decoder = new TextDecoder(); + try { + while (true) { + let length = 0; + try { length = (await handle.read(buffer, 0, buffer.length, null)).bytesRead; } + catch (error) { if (error.code !== 'EAGAIN') throw error; } + if (length) filter.write(decoder.decode(buffer.subarray(0, length), { stream: true })); + else if (ended) break; + else await new Promise(resolve => setTimeout(resolve, 10)); + } + } finally { filter.write(decoder.decode()); filter.end(); } + })(); + // Prevent an unhandled rejection while the child is still running. + void reading.catch(() => {}); + return { file, async close() { + ended = true; + try { await reading; return text; } + finally { await handle.close(); await fs.rm(directory, { force: true, recursive: true }); } + } }; + } catch (error) { await handle?.close(); await fs.rm(directory, { force: true, recursive: true }); throw error; } +} diff --git a/docker/setup/credentials/errors.mjs b/docker/setup/credentials/errors.mjs new file mode 100644 index 00000000..7ba84d45 --- /dev/null +++ b/docker/setup/credentials/errors.mjs @@ -0,0 +1,11 @@ +export class CredentialError extends Error { + constructor(message, status = 400, code = 'invalid', extra = {}) { + super(message); this.status = status; this.code = code; this.extra = extra; + } +} +export const credentialFailure = error => error instanceof CredentialError + ? { status: error.status, body: { ok: false, error: error.message, code: error.code, ...error.extra } } + : { status: 500, body: { ok: false, code: 'store', error: 'Could not access saved credentials. Check the state volume and its permissions.' } }; +export const validId = value => typeof value === 'string' && value.length <= 64 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value); +export const object = value => value !== null && typeof value === 'object' && !Array.isArray(value); +export const validText = (value, max) => typeof value === 'string' && value.isWellFormed() && value.length > 0 && value.length <= max && !/[\x00-\x1f\x7f]/.test(value); diff --git a/docker/setup/credentials/hostkeys.mjs b/docker/setup/credentials/hostkeys.mjs new file mode 100644 index 00000000..19f6bfc0 --- /dev/null +++ b/docker/setup/credentials/hostkeys.mjs @@ -0,0 +1,92 @@ +import { execFile } from 'node:child_process'; +import { createConnection, isIP } from 'node:net'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { CredentialError, validId, validText } from './errors.mjs'; + +const TYPES = ['ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-rsa']; +export const publicKey = key => key ? { type: key.type, fingerprint: key.fingerprint } : null; +export const keyFile = id => { if (!validId(id)) throw new CredentialError('Choose a valid credential name.'); return 'known_hosts/' + id; }; +export const execute = (program, args, { input, signal, timeout = 5000 } = {}) => new Promise((resolve, reject) => { + const child = execFile(program, args, { encoding: 'utf8', maxBuffer: 64 * 1024, timeout, signal, killSignal: 'SIGKILL' }, (error, stdout, stderr) => { + if (error?.code === 'ENOENT' || error?.code === 'ABORT_ERR' || error?.killed) return reject(error); + resolve({ code: error?.code || 0, stdout, stderr }); + }); + child.stdin?.on('error', error => { if (error.code !== 'EPIPE') reject(error); }); + child.stdin?.end(input || ''); +}); + +// These are public-key fingerprints, never revisions derived from passwords. +export function parseKey(line) { + const fields = String(line).trim().split(/\s+/); + if (fields[0]?.startsWith('#') || fields[0]?.startsWith('@') || fields.length < 3) return null; + const [alias, type, encoded] = fields; + if (!TYPES.includes(type) || !/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length > 16384) return null; + const bytes = Buffer.from(encoded, 'base64'); + if (bytes.length < 8 || bytes.readUInt32BE(0) !== Buffer.byteLength(type) || bytes.subarray(4, 4 + Buffer.byteLength(type)).toString() !== type) return null; + return { alias, type, key: encoded, fingerprint: 'SHA256:' + createHash('sha256').update(bytes).digest('base64').replace(/=+$/, '') }; +} +const choose = keys => [...keys].sort((a, b) => TYPES.indexOf(a.type) - TYPES.indexOf(b.type))[0] || null; +const row = (id, key) => `${id} ${key.type} ${key.key}\n`; +const result = (code, detail = {}) => ({ ok: false, code, detail }); + +export const reachHost = ({ host, port }, { signal, connect = createConnection } = {}) => new Promise(resolve => { + if (signal?.aborted) return resolve(result('timeout')); + let socket, settled = false; + const finish = value => { if (settled) return; settled = true; signal?.removeEventListener('abort', abort); socket?.destroy(); resolve(value); }; + const abort = () => finish(result('timeout')); + try { + socket = connect({ host, port }); + socket.once('connect', () => finish({ ok: true })); + socket.once('error', error => finish(result(error.code === 'ETIMEDOUT' ? 'timeout' : 'unreachable'))); + socket.setTimeout(5000, () => finish(result('timeout'))); + signal?.addEventListener('abort', abort, { once: true }); + } catch { finish(result('unreachable')); } +}); + +export function createHostKeys({ io, run = execute, reach = reachHost, home = process.env.HOME || '/home/t3', clock = () => new Date().toISOString() }) { + const validate = profile => { + if (!validText(profile?.host, 253) || !(isIP(profile.host) || /^[a-zA-Z0-9][a-zA-Z0-9.-]*$/.test(profile.host)) || !Number.isInteger(profile.port) || profile.port < 1 || profile.port > 65535) throw new CredentialError('Enter a valid host and port.'); + }; + const read = async id => { + const data = await io.read(keyFile(id), { maxBytes: 64 * 1024 }); + if (!data) return null; + const keys = data.text.split(/\r?\n/).filter(line => line.trim() && !line.startsWith('#')).map(parseKey); + if (keys.length !== 1 || !keys[0] || keys[0].alias !== id) return null; + return { ...keys[0], trustedAt: data.mtime, file: io.file(keyFile(id)) }; + }; + const scan = async (profile, { signal = AbortSignal.timeout(10000) } = {}) => { + validate(profile); + const reachable = await reach(profile, { signal }); + if (!reachable.ok) return reachable; + try { + const answer = await run('/usr/bin/ssh-keyscan', ['-T', '5', '-p', String(profile.port), '-t', 'ed25519,ecdsa,rsa', '--', profile.host], { signal, timeout: 5000 }); + const keys = answer.stdout.split(/\r?\n/).map(parseKey).filter(Boolean); + const key = choose(keys); + if (!key) return result('scan-failed'); + const checked = await run('/usr/bin/ssh-keygen', ['-lf', '-', '-E', 'sha256'], { input: `${key.type} ${key.key}\n`, signal, timeout: 2000 }); + if (checked.code !== 0 || !checked.stdout.split(/\s+/).includes(key.fingerprint)) return result('scan-failed'); + return { ok: true, key }; + } catch (error) { return result(signal.aborted || error?.killed || error?.code === 'ABORT_ERR' ? 'timeout' : 'scan-failed'); } + }; + const inspect = async (profile, options) => { + const scanned = await scan(profile, options); + if (!scanned.ok) return scanned; + let trusted = null; + if (profile.id) { try { trusted = await read(profile.id); } catch { /* unsafe files never confer trust */ } } + return { ok: true, key: scanned.key, hostKey: { state: !trusted ? 'new' : trusted.fingerprint === scanned.key.fingerprint ? 'trusted' : 'changed', presented: publicKey(scanned.key), ...(trusted ? { trusted: publicKey(trusted) } : {}) } }; + }; + const legacy = async profile => { + const file = path.join(home, '.ssh/known_hosts'); + const target = profile.port === 22 ? profile.host : `[${profile.host}]:${profile.port}`; + const answer = await run('/usr/bin/ssh-keygen', ['-F', target, '-f', file], { timeout: 5000 }); + if (answer.code !== 0) return null; + const lines = answer.stdout.split(/\r?\n/), revoked = new Set(lines.filter(line => line.startsWith('@revoked ')).map(line => line.trim().split(/\s+/)[3])); + return choose(lines.map(parseKey).filter(key => key && !revoked.has(key.key))); + }; + return { read, scan, inspect, legacy, + write: (id, key) => io.write(keyFile(id), row(id, key), { maxBytes: 64 * 1024, recover: true }), + forget: id => io.remove(keyFile(id)), + metadata: (key, carried = false) => ({ ...publicKey(key), trustedAt: clock(), carried }), + }; +} diff --git a/docker/setup/credentials/io.mjs b/docker/setup/credentials/io.mjs new file mode 100644 index 00000000..231ad670 --- /dev/null +++ b/docker/setup/credentials/io.mjs @@ -0,0 +1,94 @@ +// One writer owns changes across the store, state and trust files. Helpers use +// readOnly mode: no mkdir, chmod, migration, lock or metadata write on a read. +import * as fs from 'node:fs/promises'; +import { constants, existsSync } from 'node:fs'; +import path from 'node:path'; +import { randomUUID } from 'node:crypto'; +import { CredentialError } from './errors.mjs'; + +const localHarness = new URL('../../harness/', import.meta.url); +const harness = existsSync(new URL('lock.mjs', localHarness)) ? localHarness : new URL('file:///opt/t3-harness/'); +const [{ acquireLock }, { createFs }] = await Promise.all([import(new URL('lock.mjs', harness)), import(new URL('io.mjs', harness))]); +const queues = new Map(); +const unsafe = () => new CredentialError('A credential file is unsafe or exceeds its size limit. Repair it before continuing.', 500, 'store'); + +export function createCredentialIO({ directory, readOnly = false, effects = fs }) { + const root = path.resolve(directory); + const file = name => { + const target = path.resolve(root, name); + if (!name || target === root || !target.startsWith(root + path.sep)) throw unsafe(); + return target; + }; + const prepare = async (relative = '') => { + if (relative && relative !== 'known_hosts') throw unsafe(); + for (const target of relative ? [root, path.join(root, relative)] : [root]) { + if (!readOnly) await effects.mkdir(target, { recursive: true, mode: 0o700 }); + let stat; + try { stat = await effects.lstat(target); } catch (error) { if (readOnly && error.code === 'ENOENT') return false; throw error; } + if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid()) throw unsafe(); + if (readOnly) { if ((stat.mode & 0o777) !== 0o700) throw unsafe(); } + else if ((stat.mode & 0o777) !== 0o700) await effects.chmod(target, 0o700); + } + return true; + }; + const read = async (name, { maxBytes = 512 * 1024, missing = null } = {}) => { + if (!await prepare(name.startsWith('known_hosts/') ? 'known_hosts' : '')) return missing; + let handle; + try { + handle = await effects.open(file(name), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); + const stat = await handle.stat(); + if (!stat.isFile() || stat.nlink !== 1 || stat.uid !== process.getuid() || stat.size > maxBytes) throw unsafe(); + if (readOnly) { if ((stat.mode & 0o777) !== 0o600) throw unsafe(); } + else if ((stat.mode & 0o777) !== 0o600) await handle.chmod(0o600); + const buffer = Buffer.allocUnsafe(maxBytes + 1); let at = 0; + while (at < buffer.length) { const { bytesRead } = await handle.read(buffer, at, buffer.length - at, at); if (!bytesRead) break; at += bytesRead; } + if (at > maxBytes) throw unsafe(); + let data; + try { data = new TextDecoder('utf-8', { fatal: true }).decode(buffer.subarray(0, at)); } catch { throw unsafe(); } + return { text: data, mtime: stat.mtime.toISOString() }; + } catch (error) { if (error.code === 'ENOENT') return missing; throw error; } + finally { await handle?.close(); } + }; + const write = async (name, text, { maxBytes = 512 * 1024, recover = false } = {}) => { + if (readOnly) throw new CredentialError('Helpers cannot change saved credentials.', 500, 'read-only'); + if (Buffer.byteLength(text) > maxBytes) throw new CredentialError('Saved credentials exceed their size limit.'); + await prepare(name.startsWith('known_hosts/') ? 'known_hosts' : ''); + if (!recover) await read(name, { maxBytes }); + const target = file(name), temporary = path.join(path.dirname(target), '.' + randomUUID() + '.tmp'); + try { + const handle = await effects.open(temporary, 'wx', 0o600); + try { await handle.writeFile(text); await handle.sync(); } finally { await handle.close(); } + await effects.rename(temporary, target); + const parent = await effects.open(path.dirname(target), 'r'); + try { await parent.sync(); } finally { await parent.close(); } + } finally { await effects.rm(temporary, { force: true }); } + }; + const remove = async name => { + if (readOnly) throw new CredentialError('Helpers cannot change saved credentials.', 500, 'read-only'); + await prepare(name.startsWith('known_hosts/') ? 'known_hosts' : ''); + // Unlink the directory entry, never follow a damaged metadata symlink. + await effects.rm(file(name), { force: true }); + }; + const transaction = action => { + if (readOnly) return Promise.resolve().then(action); + const previous = queues.get(root) || Promise.resolve(); + const result = previous.catch(() => {}).then(async () => { + await prepare(); + const lockFs = { ...createFs(), writeFile: (name, data, options) => effects.writeFile(name, data, { ...options, mode: 0o600 }) }; + const ctx = { fs: lockFs, lockPath: path.join(root, 'credentials.lock'), pid: process.pid, now: Date.now, lockStaleMs: 10 * 60_000 }; + const deadline = Date.now() + 5000; + let lock; + do { + lock = await acquireLock(ctx, { id: randomUUID(), operation: 'credentials' }); + if (lock.acquired) break; + if (lock.error || Date.now() >= deadline) throw new CredentialError('Credentials are being changed. Try again in a moment.', 409, 'busy'); + await new Promise(resolve => setTimeout(resolve, 25)); + } while (true); + try { return await action(); } finally { await lock.release(); } + }); + queues.set(root, result); + void result.finally(() => { if (queues.get(root) === result) queues.delete(root); }).catch(() => {}); + return result; + }; + return { directory: root, readOnly, file, prepare, read, write, remove, transaction }; +} diff --git a/docker/setup/credentials/model.mjs b/docker/setup/credentials/model.mjs new file mode 100644 index 00000000..4e84049f --- /dev/null +++ b/docker/setup/credentials/model.mjs @@ -0,0 +1,52 @@ +import { isIP } from 'node:net'; +import { CredentialError, object, validText as text } from './errors.mjs'; +const fail = message => { throw new CredentialError(message); }; + +export function apiTarget(profile, relative) { + if (profile.type !== 'api') throw new CredentialError('Choose an API connection.'); + if (typeof relative !== 'string' || relative.length > 2048 || !relative.isWellFormed() || /[\x00-\x1f\x7f]/.test(relative) || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) throw new CredentialError('Use a path relative to the saved API address, such as projects/123.'); + const base = new URL(profile.baseUrl), target = new URL(relative || '.', base); + if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.username || target.password || target.hash) throw new CredentialError('The request must stay inside the saved API address.'); + return target; +} + +export function normalize(input, previous) { + if (!object(input)) fail('Enter connection details.'); + if (!text(input.id, 64) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(input.id)) fail('Use up to 64 lowercase letters, numbers and single hyphens for the credential name.'); + if (!['ssh', 'api'].includes(input.type)) fail('Choose SSH server or HTTP API.'); + if (previous && previous.type !== input.type) fail('Create a new connection to change its type.'); + const secret = input.secret === undefined || input.secret === '' ? previous?.secret : input.secret; + if (!text(secret, 8192)) fail('Enter a password or API key of up to 8192 characters, without line breaks.'); + if (previous && previous.id !== input.id) fail('The credential name cannot change.'); + const profile = { id: input.id, type: input.type, secret }; + if (input.type === 'ssh') { + if (!text(input.host, 253) || !(isIP(input.host) || /^[a-zA-Z0-9][a-zA-Z0-9.-]*$/.test(input.host))) fail('Enter a hostname or IP address, without a username or port.'); + if (!text(input.username, 64) || !/^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(input.username)) fail('Enter a valid SSH username.'); + if (!Number.isInteger(input.port) || input.port < 1 || input.port > 65535) fail('Enter an SSH port from 1 to 65535.'); + Object.assign(profile, { host: input.host, username: input.username, port: input.port }); + } else { + let url; + try { url = new URL(input.baseUrl); } catch { fail('Enter a complete http:// or https:// API address.'); } + if (!text(input.baseUrl, 2048) || !['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) fail('Use an HTTP or HTTPS API address without credentials, a query or a fragment.'); + if (!url.pathname.endsWith('/')) url.pathname += '/'; + profile.baseUrl = url.href; + profile.authType = input.authType ?? previous?.authType ?? 'bearer'; + if (!['bearer', 'header', 'query'].includes(profile.authType)) fail('Choose bearer token, custom header or query parameter authentication.'); + if (profile.authType !== 'bearer') { + const name = input.authName ?? previous?.authName; + if (!text(name, 128)) fail('Enter an authentication header or parameter name of up to 128 characters.'); + if (profile.authType === 'header') { + try { new Headers({ [name]: 'placeholder' }); } catch { fail('Enter a valid HTTP header name.'); } + if (['host', 'content-length', 'transfer-encoding', 'connection', 'upgrade', 'expect', 'trailer', 'te', 'accept', 'content-type'].includes(name.toLowerCase())) fail('Choose an authentication header, not a request transport or content header.'); + const prefix = input.authPrefix ?? previous?.authPrefix ?? ''; + if (typeof prefix !== 'string' || prefix.length > 128 || /[^\x20-\x7e]/.test(prefix)) fail('Use up to 128 printable ASCII characters for the optional header prefix.'); + profile.authPrefix = prefix.trim(); + } + profile.authName = name; + } + profile.testPath = input.testPath ?? previous?.testPath ?? ''; + apiTarget(profile, profile.testPath); + } + return profile; +} + diff --git a/docker/setup/credentials/redact.mjs b/docker/setup/credentials/redact.mjs new file mode 100644 index 00000000..8145b22c --- /dev/null +++ b/docker/setup/credentials/redact.mjs @@ -0,0 +1,21 @@ +export function outputFilter(secret, write) { + const values = [...new Set([secret, JSON.stringify(secret).slice(1, -1), encodeURIComponent(secret), new URLSearchParams([['', secret]]).toString().slice(1), Buffer.from(secret).toString('base64')])].filter(Boolean).sort((a, b) => b.length - a.length); + const pattern = new RegExp(values.map(value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g'); + const keep = Math.max(...values.map(value => value.length)) - 1; + let pending = ''; + const flush = final => { + let cut = final ? pending.length : Math.max(0, pending.length - keep); + for (const match of pending.matchAll(pattern)) { + if (match.index < cut && match.index + match[0].length > cut) cut = match.index + match[0].length; + } + if (cut) { write(pending.slice(0, cut).replace(pattern, '[redacted]')); pending = pending.slice(cut); } + }; + return { write(chunk) { pending += chunk; flush(false); }, end() { flush(true); } }; +} + + +export function redactText(text, secret) { + if (typeof secret !== 'string' || !secret) return text; + let result = ''; const filter = outputFilter(secret, value => { result += value; }); + filter.write(String(text)); filter.end(); return result; +} diff --git a/docker/setup/credentials/run.mjs b/docker/setup/credentials/run.mjs index a7c8a324..199a4e1d 100644 --- a/docker/setup/credentials/run.mjs +++ b/docker/setup/credentials/run.mjs @@ -1,59 +1,75 @@ import { spawn } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { Readable } from 'node:stream'; -import { CredentialError, apiTarget } from '../credentials.mjs'; -export { apiTarget } from '../credentials.mjs'; - -// Keep matches that straddle output chunks private too. Encoded JSON/API -// echoes and URL-encoded diagnostics are scrubbed alongside the literal value. -export function outputFilter(secret, write) { - const values = [...new Set([secret, JSON.stringify(secret).slice(1, -1), encodeURIComponent(secret), new URLSearchParams([['', secret]]).toString().slice(1), Buffer.from(secret).toString('base64')])].filter(Boolean).sort((a, b) => b.length - a.length); - const pattern = new RegExp(values.map(value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g'); - const keep = Math.max(...values.map(value => value.length)) - 1; - let pending = ''; - const flush = final => { - let cut = final ? pending.length : Math.max(0, pending.length - keep); - for (const match of pending.matchAll(pattern)) { - if (match.index < cut && match.index + match[0].length > cut) cut = match.index + match[0].length; - } - if (cut) { write(pending.slice(0, cut).replace(pattern, '[redacted]')); pending = pending.slice(cut); } - }; - return { write(chunk) { pending += chunk; flush(false); }, end() { flush(true); } }; -} +import { CredentialError } from './errors.mjs'; +import { apiTarget } from './model.mjs'; +import { outputFilter } from './redact.mjs'; +import { createSshDiagnostics } from './diagnostics.mjs'; +export { apiTarget } from './model.mjs'; +export { outputFilter } from './redact.mjs'; async function pump(stream, write, secret) { + if (!stream) return; stream.setEncoding('utf8'); const filter = outputFilter(secret, write); try { for await (const chunk of stream) filter.write(chunk); } finally { filter.end(); } } +const failure = code => ({ ok: false, code, detail: {} }); +function sshResult(code, diagnostics, profile, aborted) { + if (aborted || /Connection timed out|Operation timed out/i.test(diagnostics)) return failure('timeout'); + if (/REMOTE HOST IDENTIFICATION HAS CHANGED|Host key verification failed|no matching host key type/i.test(diagnostics)) return failure('host-key-changed'); + if (/Could not resolve hostname|Connection refused|No route to host|Network is unreachable|Name or service not known/i.test(diagnostics)) return failure('unreachable'); + if (/Permission denied/i.test(diagnostics)) return failure('auth-rejected'); + if (code === 0) return { ok: true, code: 'ok', detail: { user: profile.username } }; + return { ok: false, code: 'failed', detail: { line: diagnostics.trim().split(/\r?\n/).at(-1)?.slice(-160) || 'SSH did not complete the connection.' } }; +} -export async function sshRequest(profile, command, { stdout = process.stdout, stderr = process.stderr, stdin = 'inherit', probe = false, signal, spawnProcess = spawn } = {}) { - if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH connection.'); - const args = ['-T', '-p', String(profile.port), '-l', profile.username, - '-o', 'ConnectTimeout=10', '-o', 'ConnectionAttempts=1', '-o', 'NumberOfPasswordPrompts=1', - '-o', 'BatchMode=no', '-o', 'ControlPath=none', - '-o', 'StrictHostKeyChecking=accept-new', '-o', 'PreferredAuthentications=password,keyboard-interactive', - '-o', 'PubkeyAuthentication=no', '--', profile.host, ...command]; - const child = spawnProcess('/usr/bin/ssh', args, { - env: { ...process.env, SSH_ASKPASS: fileURLToPath(new URL('./askpass.sh', import.meta.url)), - SSH_ASKPASS_REQUIRE: 'force', DISPLAY: process.env.DISPLAY || 't3-credentials', T3_CREDENTIAL_PASSWORD: profile.secret }, - stdio: [stdin, 'pipe', 'pipe'], signal, - }); - const done = new Promise((resolve, reject) => { - child.once('error', () => reject(new CredentialError('SSH could not start or was interrupted.', 502))); - child.once('close', code => resolve(code ?? 1)); - }); - const discard = () => {}; - const [, , code] = await Promise.all([ - pump(child.stdout, probe ? discard : value => stdout.write(value), profile.secret), - pump(child.stderr, probe ? discard : value => stderr.write(value), profile.secret), done, - ]); - if (probe && code !== 0) throw new CredentialError('SSH connection failed. Check the address, login details and saved host key.', 502); +export async function sshRequest(profile, command, { stdout = process.stdout, stderr = process.stderr, stdin = 'inherit', probe = false, signal, spawnProcess = spawn, diagnosticsFactory = createSshDiagnostics } = {}) { + if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + if (!profile.knownHostsFile || !profile.hostKeyType) { + if (probe) return failure('host-key-untrusted'); + throw new CredentialError('Host key not trusted yet. Open Setup → Credentials and review this server’s fingerprint.', 409, 'host-key-untrusted'); + } + let diagnostics; + try { diagnostics = await diagnosticsFactory(profile.secret, probe ? () => {} : value => stderr.write(value)); } + catch { if (probe) return failure('failed'); throw new CredentialError('SSH diagnostics could not start.', 502); } + const algorithm = profile.hostKeyType === 'ssh-rsa' ? 'rsa-sha2-512,rsa-sha2-256' : profile.hostKeyType; + const args = ['-T', '-E', diagnostics.file, '-p', String(profile.port), '-l', profile.username, + '-o', 'LogLevel=ERROR', '-o', 'ConnectTimeout=10', '-o', 'ConnectionAttempts=1', '-o', 'NumberOfPasswordPrompts=1', + '-o', 'BatchMode=no', '-o', 'ControlPath=none', '-o', 'StrictHostKeyChecking=yes', + '-o', 'UserKnownHostsFile=' + profile.knownHostsFile, '-o', 'GlobalKnownHostsFile=/dev/null', + '-o', 'HostKeyAlias=' + profile.id, '-o', 'HostKeyAlgorithms=' + algorithm, + '-o', 'PreferredAuthentications=password,keyboard-interactive', '-o', 'PubkeyAuthentication=no', '--', profile.host, ...command]; + let child, code = 1, startFailed = false; + try { + child = spawnProcess('/usr/bin/ssh', args, { + env: { ...process.env, SSH_ASKPASS: fileURLToPath(new URL('./askpass.sh', import.meta.url)), + SSH_ASKPASS_REQUIRE: 'force', DISPLAY: process.env.DISPLAY || 't3-credentials', T3_CREDENTIAL_PASSWORD: profile.secret }, + stdio: [stdin, 'pipe', 'pipe'], signal, killSignal: 'SIGKILL', + }); + // Abort kills the child; waiting for close also drains both output streams. + const done = new Promise(resolve => { + child.once('error', () => { startFailed = true; }); + child.once('close', status => resolve(status ?? 1)); + }); + const discard = () => {}; + [, , code] = await Promise.all([ + pump(child.stdout, probe ? discard : value => stdout.write(value), profile.secret), + pump(child.stderr, probe ? discard : value => stderr.write(value), profile.secret), done, + ]); + } catch { startFailed = true; child?.kill('SIGKILL'); } + const diagnosticText = await diagnostics.close(); + if (probe) return sshResult(startFailed ? 1 : code, diagnosticText, profile, signal?.aborted); + if (startFailed) throw new CredentialError('SSH could not start or was interrupted.', 502); return code; } - -export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, stderr = process.stderr, probe = false, signal = AbortSignal.timeout(30000) } = {}) { +function networkCode(error, signal) { + if (signal?.aborted || error?.name === 'TimeoutError' || error?.name === 'AbortError') return 'timeout'; + for (let at = error, depth = 0; at && depth < 8; at = at.cause, depth++) if (/CERT|TLS|SELF_SIGNED|UNABLE_TO_VERIFY|DEPTH_ZERO/i.test(at.code || '')) return 'certificate'; + return 'unreachable'; +} +export async function apiRequest(profile, method, relative, { body, stdout = process.stdout, stderr = process.stderr, probe = false, signal = AbortSignal.timeout(30000), fetchRequest = fetch } = {}) { if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new CredentialError('Use GET, HEAD, POST, PUT, PATCH or DELETE.'); const target = apiTarget(profile, relative); try { @@ -61,23 +77,24 @@ export async function apiRequest(profile, method, relative, { body, stdout = pro if (profile.authType === 'query') target.searchParams.set(profile.authName, profile.secret); else if (profile.authType === 'header') headers.set(profile.authName, (profile.authPrefix ? profile.authPrefix + ' ' : '') + profile.secret); else headers.set('authorization', 'Bearer ' + profile.secret); - const response = await fetch(target, { method, redirect: 'error', signal, - headers, body }); - if (probe) { + const response = await fetchRequest(target, { method, redirect: 'manual', signal, headers, body }); + const redirected = response.status >= 300 && response.status < 400; + if (probe || redirected) { await response.body?.cancel(); - if (!response.ok) throw new CredentialError('The API did not accept the request (HTTP ' + response.status + '). Check the address and authentication settings.', 502); - } else { - if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); - if (!response.ok) stderr.write('HTTP ' + response.status + '\n'); + const code = redirected ? 'redirect' : response.ok ? 'ok' : [401, 403].includes(response.status) ? 'rejected' : response.status === 404 ? 'not-found' : 'http-error'; + if (probe) return { ok: code === 'ok', code, detail: { status: response.status } }; + throw new CredentialError('API request refused a redirect. Use the final API address in Setup → Credentials.', 502, 'redirect'); } + if (response.body) await pump(Readable.fromWeb(response.body), value => stdout.write(value), profile.secret); + if (!response.ok) stderr.write('HTTP ' + response.status + '\n'); return response.ok ? 0 : 1; } catch (error) { if (error instanceof CredentialError) throw error; - throw new CredentialError('API request failed. Check the address, certificate and network; redirects are not followed.', 502); + const code = networkCode(error, signal); + if (probe) return failure(code); + throw new CredentialError('API request failed. Check the address, certificate and network; redirects are not followed.', 502, code); } } - -export const testCredential = (profile, { signal = AbortSignal.timeout(15000) } = {}) => { - return profile.type === 'ssh' ? sshRequest(profile, ['true'], { probe: true, stdin: 'ignore', signal }) - : apiRequest(profile, 'GET', profile.testPath || '', { probe: true, signal }); -}; +export const testCredential = (profile, { signal = AbortSignal.timeout(15000), ...options } = {}) => profile.type === 'ssh' + ? sshRequest(profile, ['true'], { ...options, probe: true, stdin: 'ignore', signal }) + : apiRequest(profile, 'GET', profile.testPath || '', { ...options, probe: true, signal }); diff --git a/docker/setup/credentials/service.mjs b/docker/setup/credentials/service.mjs new file mode 100644 index 00000000..76d254f1 --- /dev/null +++ b/docker/setup/credentials/service.mjs @@ -0,0 +1,95 @@ +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { createCredentialStore } from '../credentials.mjs'; +import { createCredentialUsage } from './usage.mjs'; +import { testCredential } from './run.mjs'; +import { CredentialError, object } from './errors.mjs'; +import { cleanResult } from './state.mjs'; + +export const CREDENTIAL_ROUTES = ['/credentials', '/credentials/create', '/credentials/save', '/credentials/remove', '/credentials/scan', '/credentials/test', '/credentials/trust', '/credentials/forget-host-key']; +const fingerprint = value => typeof value === 'string' && /^SHA256:[A-Za-z0-9+/]{43}$/.test(value); +export function createCredentialsService({ store = createCredentialStore(), usage = createCredentialUsage(), test = testCredential, clock = Date.now } = {}) { + let running = 0; + const shutdown = new AbortController(), keys = store.hostKeys; + const network = async work => { + if (shutdown.signal.aborted) throw new CredentialError('Setup is restarting. Try again in a moment.', 503, 'busy'); + if (running >= 3) throw new CredentialError('Three connection checks are already running. Try again in a moment.', 409, 'busy'); + running++; + try { return await work(shutdown.signal); } finally { running--; } + }; + const scan = async (profile, signal) => keys.inspect(profile, { signal: AbortSignal.any([AbortSignal.timeout(10000), signal]) }); + const validTrust = trust => { + if (!object(trust) || !fingerprint(trust.fingerprint)) throw new CredentialError('Review and choose a host-key fingerprint before trusting it.'); + return trust.fingerprint; + }; + const trustSaved = async (id, expected, signal, revision) => { + const profile = await store.public(id); + if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + if (revision !== undefined && revision !== profile.revision) throw new CredentialError('This credential changed before its key could be trusted.', 409, 'changed'); + const scanned = await scan(profile, signal); + if (!scanned.ok) return { ok: false, code: scanned.code }; + if (scanned.key.fingerprint !== expected) throw new CredentialError('The server presented another key. Review its new fingerprint before trusting it.', 409, 'key-changed', { presented: scanned.hostKey.presented }); + const saved = await store.trust({ id, revision: profile.revision, key: scanned.key }); + return { ok: true, hostKey: saved.hostKey }; + }; + const testInput = async (input, signal) => { + const started = clock(), draft = input.draft !== undefined; + let profile = draft ? await store.draft(input) : await store.forUse(input.id), hostFingerprint = profile.hostFingerprint || null; + let result, temporary = null; + try { + if (profile.type === 'ssh') { + const scanned = await scan(draft && !profile.knownHostsFile ? { ...profile, id: undefined } : profile, signal); + if (!scanned.ok) result = scanned; + else { + const presented = scanned.hostKey.presented, trusted = scanned.hostKey.trusted; + // Explicit trust may replace a previous key for this draft only. + const agreed = draft && input.trust !== undefined ? validTrust(input.trust) : null; + if (agreed && presented.fingerprint !== agreed) result = { ok: false, code: 'host-key-changed', detail: { trusted: { type: presented.type, fingerprint: agreed }, presented } }; + else if (!agreed && scanned.hostKey.state !== 'trusted') result = { ok: false, code: trusted ? 'host-key-changed' : 'host-key-untrusted', detail: trusted ? { trusted, presented } : {}, hostKey: scanned.hostKey }; + else if (draft) { + temporary = await fs.mkdtemp(path.join(os.tmpdir(), 't3-credential-key-')); await fs.chmod(temporary, 0o700); + const file = path.join(temporary, 'known_hosts'); + await fs.writeFile(file, `${profile.id} ${scanned.key.type} ${scanned.key.key}\n`, { mode: 0o600, flag: 'wx' }); + profile = { ...profile, knownHostsFile: file, hostKeyType: scanned.key.type }; + } + } + } + result ||= await test(profile, { signal: AbortSignal.any([AbortSignal.timeout(15000), signal]) }); + const cleaned = cleanResult({ ...result, ms: clock() - started }, profile.secret); + if (!cleaned) throw new CredentialError('The connection test could not be read.', 500); + if (!draft) await store.recordTest({ id: profile.id, revision: profile.revision, hostFingerprint, result: cleaned }); + return { ok: true, result: { ...cleaned, at: new Date(clock()).toISOString() } }; + } finally { if (temporary) await fs.rm(temporary, { recursive: true, force: true }); } + }; + return { + initialize: store.initialize, + summary: store.summary, + invalidateUsage: () => usage.invalidate(), + close: () => shutdown.abort(), + async handle(route, input = {}) { + if (route === '/credentials') return { ok: true, ...await usage.annotate((await store.list()).credentials) }; + if (route === '/credentials/create' || route === '/credentials/save') { + if (input.trust !== undefined) validTrust(input.trust); + const saved = await store.save({ ...input, create: route === '/credentials/create' }); + if (input.trust !== undefined) { + try { saved.trust = await network(signal => trustSaved(saved.credential.id, input.trust.fingerprint, signal, saved.credential.revision)); } + catch (error) { saved.trust = error instanceof CredentialError ? { ok: false, code: error.code, ...(error.extra.presented ? { presented: error.extra.presented } : {}) } : { ok: false, code: 'failed' }; } + saved.credential = await store.public(saved.credential.id); + } + return { ok: true, ...saved }; + } + if (route === '/credentials/remove') return { ok: true, ...await store.remove(input) }; + if (route === '/credentials/forget-host-key') { await store.forget(input.id); return { ok: true }; } + if (route === '/credentials/test') return network(signal => testInput(input, signal)); + if (route === '/credentials/trust') { const expected = validTrust({ fingerprint: input.fingerprint }); return network(signal => trustSaved(input.id, expected, signal)); } + if (route === '/credentials/scan') return network(async signal => { + const profile = input.id === undefined ? { host: input.host, port: input.port } : await store.public(input.id); + if (input.id !== undefined && profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + const started = clock(), scanned = await scan(profile, signal); + return scanned.ok ? { ok: true, hostKey: scanned.hostKey } : { ok: true, result: { ...scanned, ms: clock() - started } }; + }); + throw new CredentialError('Credential action not found.', 404, 'not-found'); + }, + }; +} diff --git a/docker/setup/credentials/state.mjs b/docker/setup/credentials/state.mjs new file mode 100644 index 00000000..9233f4af --- /dev/null +++ b/docker/setup/credentials/state.mjs @@ -0,0 +1,38 @@ +import { object, validId } from './errors.mjs'; +import { redactText } from './redact.mjs'; +const CODES = new Set(['ok', 'unreachable', 'timeout', 'scan-failed', 'host-key-untrusted', 'host-key-changed', 'auth-rejected', 'failed', 'rejected', 'not-found', 'http-error', 'redirect', 'certificate']); +const stamp = value => typeof value === 'string' && value.length < 40 && Number.isFinite(Date.parse(value)); +const key = value => object(value) && typeof value.type === 'string' && /^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp(?:256|384|521))$/.test(value.type) && /^SHA256:[A-Za-z0-9+/]{43}$/.test(value.fingerprint || '') ? { type: value.type, fingerprint: value.fingerprint } : null; +export const emptyState = () => ({ version: 1, tests: Object.create(null), hostKeys: Object.create(null) }); + +export function cleanResult(value, secret) { + if (!object(value) || !CODES.has(value.code) || typeof value.ok !== 'boolean' || value.ok !== (value.code === 'ok')) return null; + const detail = {}, raw = object(value.detail) ? value.detail : {}; + if (Number.isInteger(raw.status) && raw.status >= 100 && raw.status <= 599) detail.status = raw.status; + if (typeof raw.user === 'string' && /^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(raw.user) && raw.user.length <= 64) detail.user = raw.user; + if (typeof raw.line === 'string') detail.line = redactText(raw.line, secret).replace(/[\x00-\x1f\x7f]/g, ' ').slice(-160); + for (const name of ['trusted', 'presented']) if (key(raw[name])) detail[name] = key(raw[name]); + const result = { ok: value.ok, code: value.code, ms: Number.isFinite(value.ms) ? Math.min(120000, Math.max(0, Math.round(value.ms))) : 0, detail }; + if (stamp(value.at)) result.at = value.at; + if (value.hostKey && ['new', 'changed', 'trusted'].includes(value.hostKey.state) && key(value.hostKey.presented)) result.hostKey = { state: value.hostKey.state, presented: key(value.hostKey.presented), ...(key(value.hostKey.trusted) ? { trusted: key(value.hostKey.trusted) } : {}) }; + return result; +} + +export function createCredentialState({ io }) { + const read = async (profiles = []) => { + const state = emptyState(); + try { + const file = await io.read('state.json'); + if (!file) return state; + const data = JSON.parse(file.text); + if (!object(data) || data.version !== 1) return state; + for (const [id, value] of Object.entries(object(data.tests) ? data.tests : {})) { + const result = cleanResult(value, profiles.find(profile => profile.id === id)?.secret); + if (validId(id) && result && stamp(result.at)) state.tests[id] = { ...result, consecutiveTimeouts: Number.isSafeInteger(value.consecutiveTimeouts) ? Math.min(100000, Math.max(0, value.consecutiveTimeouts)) : 0, ...(typeof value.revision === 'string' && /^[a-f0-9]{16}$/.test(value.revision) ? { revision: value.revision } : {}) }; + } + for (const [id, value] of Object.entries(object(data.hostKeys) ? data.hostKeys : {})) if (validId(id) && key(value) && stamp(value.trustedAt)) state.hostKeys[id] = { ...key(value), trustedAt: value.trustedAt, carried: value.carried === true }; + } catch { /* Display metadata is disposable; damaged state cannot hide credentials. */ } + return state; + }; + return { read, write: state => io.write('state.json', JSON.stringify(state, null, 2) + '\n', { recover: true }) }; +} diff --git a/docker/setup/credentials/usage.mjs b/docker/setup/credentials/usage.mjs new file mode 100644 index 00000000..b919a8b2 --- /dev/null +++ b/docker/setup/credentials/usage.mjs @@ -0,0 +1,60 @@ +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import { scanSkillFiles, readSkillFile, skillMetadata, skillProviders } from '../skills.mjs'; +import { readAgentsMd } from '../context.mjs'; + +export function credentialMentions(content) { + return new Set([...String(content).matchAll(/(?:^|[^\w-])t3-(?:ssh|api)\s+(['"]?)([a-z0-9]+(?:-[a-z0-9]+)*)\1(?![\w-])/g)].map(match => match[2])); +} +export function createCredentialUsage({ home = process.env.HOME || '/home/t3', baseDir = process.env.T3CODE_HOME || path.join(home, '.t3'), env = process.env, io = fs, scan = scanSkillFiles, readFile = readSkillFile, instructions = readAgentsMd, installed = async () => [], clock = Date.now, ttlMs = 15000, limits } = {}) { + let cache = null, pending = null, generation = 0; + const scanAll = async () => { + const providers = skillProviders(), warnings = new Set(), files = new Map(), usage = new Map(); + const installedIds = await installed().catch(() => []); + const scans = await Promise.all(providers.map(async provider => { + try { return { provider, data: await scan(provider.id, { home, env, io, limits }) }; } + catch { return { provider, data: { skills: [], warnings: ['scan-failed'] } }; } + })); + for (const { provider, data } of scans) { + if (data.warnings.length) warnings.add('Some ' + provider.name + ' skills could not be read.'); + for (const row of data.skills) { + if (row.error) { warnings.add('Some skills could not be read.'); continue; } + try { + const real = row.resolvedPath || await io.realpath(row.path); + if (!files.has(real)) files.set(real, { row, providers: new Set() }); + files.get(real).providers.add(provider.id); + } catch { warnings.add('Some skills could not be read.'); } + } + } + const add = (id, item) => { if (!usage.has(id)) usage.set(id, []); usage.get(id).push(item); }; + let bytes = 0, count = 0; + for (const [file, entry] of files) { + // A bounded second pass reads each real file once, even in shared roots. + if (++count > 512 || bytes + 65536 > 8 * 1024 * 1024) { warnings.add('The skill scan reached its safety limit; some mentions may be missing.'); break; } + try { + const read = await readFile(file, 65536, io); bytes += read.bytes; + const name = skillMetadata(read.content, path.basename(path.dirname(entry.row.path))).name; + const where = installedIds.length && installedIds.every(id => entry.providers.has(id)) ? 'All agents' : providers.filter(provider => entry.providers.has(provider.id)).map(provider => provider.name).join(', '); + for (const id of credentialMentions(read.content)) add(id, { kind: 'skill', name, where }); + } catch { warnings.add('Some skills could not be read.'); } + } + try { + const global = await instructions(io, baseDir); + if (global.error) warnings.add('Global instructions could not be read.'); + else if (global.content) for (const id of credentialMentions(global.content)) add(id, { kind: 'instructions', name: 'Global instructions' }); + } catch { warnings.add('Global instructions could not be read.'); } + return { usage, usageAt: new Date(clock()).toISOString(), usageWarnings: [...warnings] }; + }; + const read = async () => { + if (cache && clock() - cache.at < ttlMs) return cache.value; + if (pending) return pending; + const seen = generation; + const work = scanAll(); pending = work; + try { const value = await work; if (seen === generation) cache = { at: clock(), value }; return value; } + finally { if (pending === work) pending = null; } + }; + return { invalidate() { generation++; cache = null; pending = null; }, async annotate(credentials) { + const value = await read(); + return { credentials: credentials.map(credential => ({ ...credential, usedIn: value.usage.get(credential.id) || [] })), usageAt: value.usageAt, usageWarnings: value.usageWarnings }; + } }; +} diff --git a/docker/setup/server.mjs b/docker/setup/server.mjs index 8eaddfca..e6842aed 100644 --- a/docker/setup/server.mjs +++ b/docker/setup/server.mjs @@ -39,7 +39,8 @@ import { createMcpService } from "./mcp.mjs"; import { clientAddress } from "./client-address.mjs"; import { newKey, readKeyFile, writeKeyFile } from "./setup-key.mjs"; import { createCredentialStore, credentialFailure, CredentialError } from "./credentials.mjs"; -import { testCredential } from "./credentials/run.mjs"; +import { createCredentialsService, CREDENTIAL_ROUTES } from "./credentials/service.mjs"; +import { createCredentialUsage } from "./credentials/usage.mjs"; import { connectState, createConnectPreferences, jsonFrom, parseLinkOutput } from "./connect.mjs"; import { checkReaches, clearSaved, parsePublicUrl, platformUrl, readSaved, resolvePublicUrl, writeSaved, @@ -69,9 +70,7 @@ const SINGLE_PORT = Number(process.env.T3_SINGLE_PORT) || null; const SINGLE_PREFIX = BASE_PATH ? (BASE_PATH.startsWith("/") ? BASE_PATH : `/${BASE_PATH}`) : "/__setup"; // Where T3 Code keeps its state; the volume a user mounts is the home around it. const STATE_DIR = process.env.T3CODE_HOME || `${process.env.HOME || "/home/t3"}/.t3`; -const credentials = createCredentialStore(); -const credentialShutdown = new AbortController(); -let credentialTests = 0; +const credentialStore = createCredentialStore(); const VOLUME = process.env.HOME || STATE_DIR.replace(/\/\.t3\/?$/, "") || STATE_DIR; const WORKSPACE = process.env.T3_WORKSPACE || "/workspace"; // The setup key and where it came from (setup-key.mjs): "env" for @@ -536,6 +535,10 @@ const skillsService = createSkillsService({ home: CONTEXT_HOME, env: process.env const mcpService = createMcpService({ home: CONTEXT_HOME, env: process.env, baseDir: STATE_DIR, io: await contextFs(), }); +const credentials = createCredentialsService({ store: credentialStore, usage: createCredentialUsage({ + home: CONTEXT_HOME, baseDir: STATE_DIR, env: process.env, io: await contextFs(), + installed: async () => ((await harnessCache.snapshotCheap()).harnesses || []).filter(row => row.installed).map(row => row.id), +}) }); let filesPromise, filesInstance, filesPayloads = 0; const loadFiles = () => filesPromise ??= loadStorage().then(storage => createFilesService({ home: CONTEXT_HOME, workspace: WORKSPACE, stateDir: STATE_DIR, env: process.env, storage, processSnapshot: harnessModule.processSnapshot, t3: t3Api, recordEvent, withStopped: action => filesHold.withStopped(action), @@ -932,6 +935,8 @@ const status = async () => { updates: { refreshing: latestCache.refreshing(), manual: latestCache.manualPending(), errors: latestCache.errors(), checkedAt: latestCache.checkedAt() }, // Every other tool in the global mise config, added here or with `mise use -g`. packages: withLatest("package", packageRows), + // Local credential attention only. This never scans skills or connects. + credentials: await attemptTimed('credentials', () => credentials.summary(), 1200, { count: null, attention: [], error: 'Saved credentials could not be read.' }), // Global instruction metadata; the editor fetches contents on demand. // Shared MCP metadata rides alongside; server entries stay server-side. context: await attempt("context", async () => { @@ -2186,7 +2191,7 @@ const cancelLifecycle = (target, rawId) => { return { http: 404, body: { ok: false, code: "not-running", error: "Nothing is running or waiting for that row." } }; }; -const ROUTES = [...FILES_ROUTES, "/credentials", "/credentials/create", "/credentials/save", "/credentials/remove", "/credentials/test", "/login", "/logout", "/hello", "/status", "/pair", "/revoke", "/devices/rename", "/ports", +const ROUTES = [...FILES_ROUTES, ...CREDENTIAL_ROUTES, "/login", "/logout", "/hello", "/status", "/pair", "/revoke", "/devices/rename", "/ports", "/storage/versions/prune", "/storage/versions", "/storage/refresh", "/storage/clean/preview", "/storage/clean", "/storage/policy", "/storage", "/public-url/clear", "/public-url", "/setup-key/reveal", "/setup-key/replace", "/connect/unlink", "/connect/preferences", "/t3/restart", "/t3/updates/check", "/t3/update", "/ports/expose", "/ports/unexpose", @@ -2533,24 +2538,12 @@ const server = createServer(async (req, res) => { if (route === '/credentials' || route.startsWith('/credentials/')) { if (req.method !== (route === '/credentials' ? 'GET' : 'POST')) return sendJson(res, 405, { ok: false, error: 'Use the supported method for this credential action.' }); try { - if (route === '/credentials') return sendJson(res, 200, { ok: true, ...await credentials.list() }); + if (route === '/credentials') return sendJson(res, 200, await credentials.handle(route)); let input; try { input = JSON.parse(await readBody(req)); } - catch (error) { return sendJson(res, error.message === 'body too large' ? 413 : 400, { ok: false, error: 'Send connection details as a JSON object of at most 64 KiB.' }); } - if (!input || typeof input !== 'object' || Array.isArray(input)) throw new CredentialError('Send connection details as a JSON object.'); - if (route === '/credentials/create' || route === '/credentials/save') return sendJson(res, 200, { ok: true, ...await credentials.save({ ...input, create: route === '/credentials/create' }) }); - if (route === '/credentials/remove') return sendJson(res, 200, { ok: true, ...await credentials.remove(input) }); - if (route === '/credentials/test') { - if (credentialTests >= 3) throw new CredentialError('Other connections are being tested. Try again in a moment.', 409); - credentialTests++; - try { - const snapshot = await credentials.list(); - if (snapshot.revision !== input.revision) throw new CredentialError('Connections changed. Reload the list before testing again.', 409); - await testCredential(await credentials.forUse(input.id), { signal: AbortSignal.any([AbortSignal.timeout(15000), credentialShutdown.signal]) }); - return sendJson(res, 200, { ok: true, message: 'Connection succeeded.' }); - } finally { credentialTests--; } - } - return sendJson(res, 404, { ok: false, error: 'Credential action not found.' }); + catch (error) { return sendJson(res, error.message === 'body too large' ? 413 : 400, { ok: false, code: 'invalid', error: 'Send credential details as a JSON object of at most 64 KiB.' }); } + if (!input || typeof input !== 'object' || Array.isArray(input)) throw new CredentialError('Send credential details as a JSON object.'); + return sendJson(res, 200, await credentials.handle(route, input)); } catch (error) { const failure = credentialFailure(error); return sendJson(res, failure.status, failure.body); } } @@ -2808,6 +2801,7 @@ const server = createServer(async (req, res) => { : route === "/context/skills/save" ? await skillsService.save(input.provider, input.id, input.revision, input.content) : route === "/context/skills/state" ? await skillsService.setState(input.provider, input.id, input.stateRevision, input.enabled, input.state) : await skillsService.remove(input.provider, input.id, input.revision, input.removalRevision); + credentials.invalidateUsage(); if (!["/context/skills/check-update", "/context/skills/source", "/context/skills/update/preview", "/context/skills/plan", "/context/skills/discard"].includes(route)) recordEvent("context.saved", route === "/context/skills/update" ? "Updated a repository skill; review the installation result" : route === "/context/skills/hooks/state" ? "Changed a Codex plugin hook setting" : route === "/context/skills/install" ? "Imported local skills; review individual installation results" : route === "/context/skills/remove" ? "Removed a local skill installation" : route === "/context/skills/state" ? "Changed native skill availability" : "Saved a local skill"); return sendJson(res, 200, result); } catch (error) { @@ -2880,6 +2874,7 @@ const server = createServer(async (req, res) => { // Allow encoding overhead here; decoded instruction size is validated below. const input = JSON.parse((await readBody(req, 6 * 64 * 1024 + 4096)) || "{}"); const fs = await contextFs(); + credentials.invalidateUsage(); if (input.provider !== undefined) { const options = { home: CONTEXT_HOME, env: process.env }; const result = input.mode !== undefined @@ -3131,7 +3126,7 @@ const server = createServer(async (req, res) => { // tracking them - a sign-in nobody can finish, a URL nobody can stop - so // they go when the service does, however it goes. const stopChildren = () => { - credentialShutdown.abort(); + credentials.close(); filesInstance?.stop(); for (const session of sessions.values()) { if (!TERMINAL_STATES.has(session.state)) { @@ -3147,6 +3142,9 @@ for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"]) { process.on(signal, () => process.exit(0)); } +// The setup service alone migrates legacy stores before serving requests. +try { await credentials.initialize(); } +catch { console.warn('[setup] Saved credentials need attention; open Credentials to inspect the store.'); } server.listen(PORT, "0.0.0.0", () => { console.log(`[setup] listening on 0.0.0.0:${PORT}`); // Background facts: the storage check now, release lookups shortly after diff --git a/docs/server-credentials.md b/docs/credentials.md similarity index 100% rename from docs/server-credentials.md rename to docs/credentials.md diff --git a/scripts/credentials-smoke.mjs b/scripts/credentials-smoke.mjs index e2ccaf2f..0b5e2fe4 100644 --- a/scripts/credentials-smoke.mjs +++ b/scripts/credentials-smoke.mjs @@ -26,14 +26,14 @@ try { await access('/opt/t3-setup/credentials/askpass.sh', constants.X_OK); for (const cli of ['t3-ssh', 't3-api']) assert.match((await run('/usr/local/bin/' + cli, ['--help'])).stdout, /Manage connections/); let snapshot = await request('/credentials'); - await request('/credentials/create', { revision: snapshot.revision, profile: { id, label: 'Disposable image check', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', authType: 'header', authName: 'X-API-Key', testPath: 'account', secret } }); + await request('/credentials/create', { credential: { id, label: 'Disposable image check', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', authType: 'header', authName: 'X-API-Key', testPath: 'account', secret } }); created = true; snapshot = await request('/credentials'); - assert.equal(snapshot.profiles.find(profile => profile.id === id).hasSecret, true); - await request('/credentials/test', { id, revision: snapshot.revision }); + assert.equal(snapshot.credentials.find(profile => profile.id === id).hasSecret, true); + assert.equal((await request('/credentials/test', { id })).result.code, 'ok'); const { stdout, stderr } = await run('/usr/local/bin/t3-api', [id, 'GET', 'projects']); assert.deepEqual(JSON.parse(stdout), { status: 'ok', echo: '[redacted]' }); assert.equal(stderr, ''); console.log('PASS saved API credentials and installed SSH/API helpers'); } finally { - try { if (created) { const snapshot = await request('/credentials'); await request('/credentials/remove', { id, revision: snapshot.revision }); } } + try { if (created) { const snapshot = await request('/credentials'); await request('/credentials/remove', { id, revision: snapshot.credentials.find(row => row.id === id).revision }); } } finally { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); } } diff --git a/tests/console-model.test.mjs b/tests/console-model.test.mjs index 565b134e..0dfef2d0 100644 --- a/tests/console-model.test.mjs +++ b/tests/console-model.test.mjs @@ -1510,3 +1510,14 @@ test("update check failures can be read for every source at once", () => { assert.equal(M.updateCheckView(status, null).failures.length, 2); assert.equal(M.updateCheckView(status, "harness").failures.length, 1); }); + +test('Credentials attention feeds Overview, navigation and host badges without counting untested credentials', () => { + const base = { credentials: { count: 3, attention: [{ id: 'build-server', code: 'host-key-untrusted' }, { id: 'project-api', code: 'rejected' }] } }; + assert.deepEqual(plain(M.navBadges(base).credentials), { tone: 'warn', count: 2 }); + const items = plain(M.needsYou(base)).filter(row => row.target === 'credential'); + assert.equal(items.length, 2); assert.equal(items[0].id, 'project-api'); + assert.equal(items[1].action.route, 'credentials/build-server'); assert.equal(items[1].tone, 'warn'); + assert.equal(M.navBadges({ credentials: { count: 3, attention: [] } }).credentials, null); + assert.equal(M.credentialState({ type: 'ssh', hostKey: null, test: { code: 'ok' } }).code, 'host-key-untrusted'); + assert.equal(M.credentialState({ type: 'api', test: { code: 'rejected', detail: { status: 401 } } }).label, 'Rejected · HTTP 401'); +}); diff --git a/tests/credentials-api.test.mjs b/tests/credentials-api.test.mjs index 77df8dbf..2797e796 100644 --- a/tests/credentials-api.test.mjs +++ b/tests/credentials-api.test.mjs @@ -8,7 +8,7 @@ import { credentialsFixture } from './fixtures/credentials.mjs'; test('credential HTTP boundary is authenticated, write-only and revision checked', { timeout: 20000 }, async t => { const f = await credentialsFixture(); t.after(f.close); - for (const route of ['/credentials', '/credentials/create', '/credentials/save', '/credentials/test', '/credentials/remove']) { + for (const route of ['/credentials', '/credentials/create', '/credentials/save', '/credentials/test', '/credentials/remove', '/credentials/scan', '/credentials/trust', '/credentials/forget-host-key']) { const method = route === '/credentials' ? 'GET' : 'POST'; assert.equal((await fetch(f.base + route, { method })).status, 401); } @@ -16,27 +16,27 @@ test('credential HTTP boundary is authenticated, write-only and revision checked assert.equal((await f.request('/credentials', {})).status, 405); assert.equal((await f.request('/credentials/create')).status, 405); const initial = await (await f.request('/credentials')).json(); - assert.deepEqual(initial.profiles, []); + assert.deepEqual(initial.credentials, []); const secret = 'fixture-http-credential-456'; const profile = { id: 'staging-server', label: 'Staging server', type: 'ssh', host: '192.0.2.2', username: 'root', port: 22, secret }; - const created = await (await f.request('/credentials/create', { profile, revision: initial.revision })).json(); + const created = await (await f.request('/credentials/create', { credential: profile })).json(); assert.equal(created.ok, true); assert.equal(JSON.stringify(created).includes(secret), false); const snapshotResponse = await f.request('/credentials'); assert.equal(snapshotResponse.headers.get('cache-control'), 'no-store'); const snapshot = await snapshotResponse.json(); assert.equal(JSON.stringify(snapshot).includes(secret), false); - assert.equal(snapshot.profiles[0].hasSecret, true); - assert.equal((await f.request('/credentials/save', { profile, revision: initial.revision })).status, 409); - assert.equal((await f.request('/credentials/create', { profile, revision: snapshot.revision })).status, 409); - assert.equal((await f.request('/credentials/save', { profile: { ...profile, secret: '' }, revision: snapshot.revision })).status, 200); + assert.equal(snapshot.credentials[0].hasSecret, true); + assert.equal((await f.request('/credentials/save', { credential: profile, revision: 'stale' })).status, 409); + assert.equal((await f.request('/credentials/create', { credential: profile })).status, 409); + assert.equal((await f.request('/credentials/save', { credential: { ...profile, secret: '' }, revision: created.credential.revision })).status, 200); const malformed = await fetch(f.base + '/credentials/create', { method: 'POST', headers: { 'x-t3-setup-key': 'credential-fixture-key' }, body: '{"secret":"' + secret }); assert.equal(malformed.status, 400); assert.equal((await malformed.text()).includes(secret), false); const oversized = await fetch(f.base + '/credentials/create', { method: 'POST', headers: { 'x-t3-setup-key': 'credential-fixture-key' }, body: JSON.stringify({ secret: secret.repeat(4000) }) }); assert.equal(oversized.status, 413); assert.equal((await oversized.text()).includes(secret), false); assert.equal((await f.request('/credentials/create', null)).status, 400); const latest = await (await f.request('/credentials')).json(); - assert.equal((await f.request('/credentials/test', { id: profile.id, revision: initial.revision })).status, 409); - assert.equal((await f.request('/credentials/remove', { id: profile.id, revision: latest.revision })).status, 200); - assert.deepEqual((await (await f.request('/credentials')).json()).profiles, []); + assert.equal((await f.request('/credentials/test', { id: profile.id, draft: { ...profile, id: 'different', secret: '' } })).status, 400); + assert.equal((await f.request('/credentials/remove', { id: profile.id, revision: latest.credentials[0].revision })).status, 200); + assert.deepEqual((await (await f.request('/credentials')).json()).credentials, []); assert.equal(f.logs().includes(secret), false); }); @@ -53,12 +53,12 @@ test('saved API token works through the CLI and connection test without returnin server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); const initial = await (await f.request('/credentials')).json(); - const saved = await (await f.request('/credentials/create', { revision: initial.revision, profile: { id: 'project-api', label: 'Project API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } })).json(); + const saved = await (await f.request('/credentials/create', { credential: { id: 'project-api', label: 'Project API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } })).json(); const probe = await f.request('/credentials/test', { id: 'project-api', revision: saved.revision }); assert.equal(probe.status, 200); assert.equal((await probe.text()).includes(secret), false); failAuth = true; const rejected = await f.request('/credentials/test', { id: 'project-api', revision: saved.revision }); - assert.equal(rejected.status, 502); assert.equal((await rejected.text()).includes(secret), false); + assert.equal(rejected.status, 200); assert.equal((await rejected.clone().json()).result.code, 'rejected'); assert.equal((await rejected.text()).includes(secret), false); failAuth = false; const helperEnv = { ...f.env, T3_INFRA_NODE: process.execPath, T3_CREDENTIAL_CLI: fileURLToPath(new URL('../docker/setup/credentials/cli.mjs', import.meta.url)) }; const child = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-api', import.meta.url)), 'project-api', 'POST', 'projects', '--stdin'], { env: helperEnv, stdio: ['pipe', 'pipe', 'pipe'] }); diff --git a/tests/credentials-service.test.mjs b/tests/credentials-service.test.mjs new file mode 100644 index 00000000..c6c1fb1a --- /dev/null +++ b/tests/credentials-service.test.mjs @@ -0,0 +1,152 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { createCredentialStore } from '../docker/setup/credentials.mjs'; +import { createCredentialIO } from '../docker/setup/credentials/io.mjs'; +import { createHostKeys, parseKey, reachHost } from '../docker/setup/credentials/hostkeys.mjs'; +import { createCredentialsService } from '../docker/setup/credentials/service.mjs'; +import { apiRequest, sshRequest } from '../docker/setup/credentials/run.mjs'; +import { credentialKey } from './fixtures/credential-keys.mjs'; +const ssh = { id: 'build-server', type: 'ssh', host: '192.0.2.10', port: 22, username: 'deploy', secret: 'synthetic-pass' }; +const api = { id: 'project-api', type: 'api', baseUrl: 'https://api.example.test/v1/', secret: 'synthetic-token' }; +const usage = { invalidate() {}, async annotate(credentials) { return { credentials: credentials.map(row => ({ ...row, usedIn: [] })), usageAt: new Date().toISOString(), usageWarnings: [] }; } }; +async function fixture(t, options = {}) { + const directory = await fs.mkdtemp(path.join(os.tmpdir(), 'credential-service-')), io = createCredentialIO({ directory }); + const key = credentialKey(); let offered = key, reachable = { ok: true }, signins = 0, scans = 0; + const keys = createHostKeys({ io, reach: async () => reachable, run: async (program, args) => { + if (program.endsWith('keyscan')) { scans++; if (!offered) return { code: 1, stdout: '' }; return { code: 0, stdout: `host ${offered.type} ${offered.key}\n` }; } + return { code: 0, stdout: offered ? '256 ' + offered.fingerprint + ' (ED25519)' : '' }; + } }); + const store = createCredentialStore({ directory, io, hostKeys: keys }); + const service = createCredentialsService({ store, usage, test: async (profile, options) => { signins++; return options.test ? options.test(profile) : { ok: true, code: 'ok', detail: { user: profile.username } }; }, ...options }); + t.after(() => { service.close(); return fs.rm(directory, { recursive: true, force: true }); }); + return { directory, io, key, keys, store, service, create: credential => store.save({ create: true, credential }), offered(value) { offered = value; }, reachable(value) { reachable = value; }, get signins() { return signins; }, get scans() { return scans; } }; +} + +test('scan only reads host details and never signs in, persists state or reads a secret', async t => { + const f = await fixture(t); await f.create(ssh); + const before = await fs.readFile(path.join(f.directory, 'state.json'), 'utf8'); + const result = await f.service.handle('/credentials/scan', { id: ssh.id }); + assert.equal(result.hostKey.state, 'new'); assert.equal(result.hostKey.presented.fingerprint, f.key.fingerprint); assert.equal(f.signins, 0); + assert.equal(await fs.readFile(path.join(f.directory, 'state.json'), 'utf8'), before); + assert.equal(JSON.stringify(result).includes(ssh.secret), false); +}); + +test('saved tests block before authentication until explicit fresh fingerprint trust', async t => { + const f = await fixture(t), saved = (await f.create(ssh)).credential; + let result = await f.service.handle('/credentials/test', { id: ssh.id }); + assert.equal(result.ok, true); assert.equal(result.result.code, 'host-key-untrusted'); assert.equal(f.signins, 0); + await f.service.handle('/credentials/trust', { id: ssh.id, fingerprint: f.key.fingerprint }); + result = await f.service.handle('/credentials/test', { id: ssh.id }); + assert.equal(result.result.code, 'ok'); assert.equal(f.signins, 1); + const next = credentialKey(); f.offered(next); + result = await f.service.handle('/credentials/test', { id: ssh.id }); + assert.equal(result.result.code, 'host-key-changed'); assert.equal(f.signins, 1); + assert.equal(result.result.detail.trusted.fingerprint, f.key.fingerprint); + assert.equal(result.result.detail.presented.fingerprint, next.fingerprint); + assert.equal((await f.store.public(ssh.id)).revision, saved.revision); + await assert.rejects(f.service.handle('/credentials/trust', { id: ssh.id, fingerprint: f.key.fingerprint }), { status: 409, code: 'key-changed' }); + assert.equal((await f.store.public(ssh.id)).hostKey.fingerprint, f.key.fingerprint); +}); + +test('draft tests pin only the fingerprint explicitly approved and leave no saved traces', async t => { + let calls = 0, temporary; + const f = await fixture(t, { test: async profile => { + calls++; temporary = path.dirname(profile.knownHostsFile); + assert.equal((await fs.stat(profile.knownHostsFile)).mode & 0o777, 0o600); + assert.equal(await fs.readFile(profile.knownHostsFile, 'utf8'), `${ssh.id} ${f.key.type} ${f.key.key}\n`); + return { ok: true, code: 'ok', detail: { user: profile.username } }; + } }); + const before = await fs.readdir(f.directory); + let result = await f.service.handle('/credentials/test', { draft: ssh }); assert.equal(result.result.code, 'host-key-untrusted'); + result = await f.service.handle('/credentials/test', { draft: ssh, trust: { fingerprint: f.key.fingerprint } }); + assert.equal(result.result.code, 'ok'); assert.equal(calls, 1); + await assert.rejects(fs.stat(temporary), { code: 'ENOENT' }); + assert.deepEqual(await fs.readdir(f.directory), before); + f.offered(credentialKey()); + result = await f.service.handle('/credentials/test', { draft: ssh, trust: { fingerprint: f.key.fingerprint } }); + assert.equal(result.result.code, 'host-key-changed'); assert.equal(calls, 1); +}); + +test('a changed draft target must get fresh trust even when the host offers the same key', async t => { + const f = await fixture(t); const saved = (await f.create(ssh)).credential; + await f.store.trust({ id: ssh.id, revision: saved.revision, key: f.key }); + let answer = await f.service.handle('/credentials/test', { id: ssh.id, draft: { ...ssh, secret: '' } }); + assert.equal(answer.result.code, 'ok'); + answer = await f.service.handle('/credentials/test', { id: ssh.id, draft: { ...ssh, host: 'other-host', secret: '' } }); + assert.equal(answer.result.code, 'host-key-untrusted'); + for (const draft of [{ ...ssh, id: 'other', secret: '' }, { ...api, id: ssh.id, secret: '' }]) await assert.rejects(f.service.handle('/credentials/test', { id: ssh.id, draft }), { status: 400 }); +}); + +test('saving comes before optional trust and exposes partial trust failure honestly', async t => { + const f = await fixture(t), oldKey = f.key; f.offered(credentialKey()); + const answer = await f.service.handle('/credentials/create', { credential: ssh, trust: { fingerprint: oldKey.fingerprint } }); + assert.equal(answer.ok, true); assert.equal(answer.credential.id, ssh.id); assert.equal(answer.trust.code, 'key-changed'); + assert.equal(answer.credential.hostKey, null); assert.equal((await f.store.list()).credentials.length, 1); + const saved = await f.service.handle('/credentials/save', { credential: { ...ssh, secret: '' }, revision: answer.credential.revision, trust: { fingerprint: answer.trust.presented.fingerprint } }); + assert.equal(saved.trust.ok, true); assert.equal(saved.credential.hostKey.fingerprint, answer.trust.presented.fingerprint); +}); + +test('a credential edited during trust scanning cannot acquire trust for an obsolete target', async t => { + const f = await fixture(t); const saved = (await f.create(ssh)).credential; + const oldInspect = f.keys.inspect; + f.keys.inspect = async (...args) => { const answer = await oldInspect(...args); await f.store.save({ credential: { ...ssh, host: 'other-host' }, revision: saved.revision }); return answer; }; + await assert.rejects(f.service.handle('/credentials/trust', { id: ssh.id, fingerprint: f.key.fingerprint }), { code: 'changed' }); + assert.equal((await f.store.public(ssh.id)).hostKey, null); +}); + +test('unreachable, timeout and scans without keys never attempt authentication', async t => { + const f = await fixture(t); await f.create(ssh); + for (const code of ['unreachable', 'timeout']) { f.reachable({ ok: false, code, detail: {} }); assert.equal((await f.service.handle('/credentials/test', { id: ssh.id })).result.code, code); } + f.reachable({ ok: true }); f.offered(null); + assert.equal((await f.service.handle('/credentials/test', { id: ssh.id })).result.code, 'scan-failed'); assert.equal(f.signins, 0); +}); + +test('three in-flight tests are allowed; excess checks are refused and shutdown aborts all', async t => { + const waiting = [], f = await fixture(t, { test: async (_profile, { signal }) => new Promise(resolve => { waiting.push(() => resolve({ ok: true, code: 'ok' })); signal.addEventListener('abort', () => resolve({ ok: false, code: 'timeout' }), { once: true }); }) }); + await f.create(api); + const jobs = [1, 2, 3].map(() => f.service.handle('/credentials/test', { id: api.id })); + // All three reserve their lease synchronously before any store read. + await assert.rejects(f.service.handle('/credentials/test', { id: api.id }), { status: 409, code: 'busy' }); + while (waiting.length < 3) await new Promise(resolve => setImmediate(resolve)); + f.service.close(); const results = await Promise.all(jobs); assert.ok(results.every(answer => answer.result.code === 'timeout')); + await assert.rejects(f.service.handle('/credentials/test', { id: api.id }), { status: 503 }); +}); + +for (const [status, code] of [[200, 'ok'], [204, 'ok'], [401, 'rejected'], [403, 'rejected'], [404, 'not-found'], [500, 'http-error'], [302, 'redirect']]) test('API test classifies HTTP ' + status + ' without a response body or header', async () => { + let cancelled = 0; + const result = await apiRequest(api, 'GET', '', { probe: true, fetchRequest: async (_url, options) => { + assert.equal(options.redirect, 'manual'); return { status, ok: status < 300, body: { cancel() { cancelled++; } }, headers: { secret: api.secret } }; + } }); + assert.equal(result.code, code); assert.deepEqual(result.detail, { status }); assert.equal(cancelled, 1); assert.equal(JSON.stringify(result).includes(api.secret), false); +}); +for (const [error, code] of [[{ cause: { code: 'CERT_HAS_EXPIRED' } }, 'certificate'], [{ cause: { code: 'ECONNREFUSED' } }, 'unreachable'], [{ name: 'AbortError' }, 'timeout']]) test('API test classifies ' + code + ' without returning diagnostics', async () => { + const result = await apiRequest(api, 'GET', '', { probe: true, fetchRequest: async () => { throw { ...error, message: api.secret }; } }); assert.equal(result.code, code); assert.deepEqual(result.detail, {}); +}); + +test('SSH helper refuses an untrusted credential before starting a process', async () => { + let spawned = false; + await assert.rejects(sshRequest(ssh, ['true'], { spawnProcess() { spawned = true; } }), { code: 'host-key-untrusted' }); + assert.equal(spawned, false); +}); + +test('host key parser ignores markers and fingerprints a real public key', () => { + const key = credentialKey(); assert.equal(parseKey('host ' + key.type + ' ' + key.key).fingerprint, key.fingerprint); + for (const line of ['# comment', '@revoked host ' + key.type + ' ' + key.key, 'host bad key', 'host ssh-ed25519 bad']) assert.equal(parseKey(line), null); +}); + +for (const [clientLine, remoteLine, status, code] of [ + ['', 'Permission denied\n', 0, 'ok'], ['', 'Permission denied\n', 1, 'failed'], + ['Permission denied (password).', '', 255, 'auth-rejected'], ['Host key verification failed.', '', 255, 'host-key-changed'], + ['ssh: connect to host: Connection refused', '', 255, 'unreachable'], ['Connection timed out', '', 255, 'timeout'], + ['unexpected synthetic-pass message', '', 255, 'failed'], +]) test('SSH client diagnostics classify ' + code + ' independently of remote stderr', async () => { + const { spawn } = await import('node:child_process'); + const result = await sshRequest({ ...ssh, knownHostsFile: '/synthetic/pinned-key', hostKeyType: 'ssh-ed25519' }, ['true'], { probe: true, stdin: 'ignore', spawnProcess(_program, args, options) { + const log = args[args.indexOf('-E') + 1]; + return spawn(process.execPath, ['-e', "require('node:fs').writeFileSync(process.env.CLIENT_LOG,process.env.CLIENT_LINE);process.stderr.write(process.env.REMOTE_LINE);process.exitCode=Number(process.env.RESULT_CODE)"], { ...options, env: { ...options.env, CLIENT_LOG: log, CLIENT_LINE: clientLine, REMOTE_LINE: remoteLine, RESULT_CODE: String(status) } }); + } }); + assert.equal(result.code, code); assert.equal(JSON.stringify(result).includes(ssh.secret), false); +}); diff --git a/tests/credentials-store.test.mjs b/tests/credentials-store.test.mjs new file mode 100644 index 00000000..9627a137 --- /dev/null +++ b/tests/credentials-store.test.mjs @@ -0,0 +1,162 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { createCredentialStore, credentialFailure } from '../docker/setup/credentials.mjs'; +import { createCredentialIO } from '../docker/setup/credentials/io.mjs'; +import { createHostKeys } from '../docker/setup/credentials/hostkeys.mjs'; +import { credentialKey } from './fixtures/credential-keys.mjs'; +const ssh = { id: 'build-server', label: 'No longer stored', type: 'ssh', host: '192.0.2.10', port: 22, username: 'deploy', secret: 'synthetic-private-password' }; +const api = { id: 'project-api', type: 'api', baseUrl: 'https://api.example.test/v1/', secret: 'synthetic-private-token' }; +async function fixture(t, options = {}) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 'credential-store-')), directory = path.join(root, 'credentials'); + const io = createCredentialIO({ directory, effects: options.effects || fs }), key = credentialKey(); + const hostKeys = createHostKeys({ io, home: root, ...options.keys }); + const store = createCredentialStore({ directory, io, hostKeys, ...options.store }); + t.after(() => fs.rm(root, { recursive: true, force: true })); + return { root, directory, io, hostKeys, key, store, create: credential => store.save({ credential, create: true }) }; +} + +test('v2 stores immutable names, independent random revisions and server-owned dates', async t => { + let ms = Date.parse('2026-10-30T10:00:00Z'); + const { store, create, directory } = await fixture(t, { store: { clock: () => ms } }); + const a = (await create({ ...ssh, revision: 'bad', createdAt: 'bad' })).credential; + const b = (await create(api)).credential; + assert.match(a.revision, /^[a-f0-9]{16}$/); assert.notEqual(a.revision, b.revision); + assert.equal(a.createdAt, '2026-10-30T10:00:00.000Z'); assert.equal(a.secretChangedAt, a.createdAt); + ms += 1000; + const edited = (await store.save({ credential: { ...ssh, secret: '', username: 'other' }, revision: a.revision })).credential; + assert.equal(edited.createdAt, a.createdAt); assert.notEqual(edited.updatedAt, a.updatedAt); assert.equal(edited.secretChangedAt, a.secretChangedAt); + await store.save({ credential: { ...api, secret: '' }, revision: b.revision }); + const raw = JSON.parse(await fs.readFile(path.join(directory, 'credentials.json'), 'utf8')); + assert.equal(raw.version, 2); assert.equal(Object.hasOwn(raw.profiles[0], 'label'), false); + assert.equal(JSON.stringify(await store.list()).includes(ssh.secret), false); + await assert.rejects(store.save({ credential: { ...ssh, type: 'api', baseUrl: api.baseUrl }, revision: edited.revision }), /change its type/); + await assert.rejects(store.draft({ id: ssh.id, draft: { ...ssh, id: 'different', secret: '' } }), /name cannot change/); + await assert.rejects(store.draft({ id: ssh.id, draft: { ...api, id: ssh.id, secret: '' } }), /change its type/); + await assert.rejects(store.remove({ id: '../escape', revision: '' }), { code: 'invalid' }); +}); + +test('migration drops labels, sets mtime dates and carries a single existing key without changing user known_hosts', async t => { + const carried = credentialKey(), { directory, root, io, store } = await fixture(t, { keys: { run: async (program, args) => { + assert.equal(program, '/usr/bin/ssh-keygen'); assert.deepEqual(args.slice(0, 2), ['-F', '[192.0.2.10]:2222']); + return { code: 0, stdout: '# comment\n|1|hash|hash ' + carried.type + ' ' + carried.key + '\n' }; + } } }); + await io.prepare(); await fs.mkdir(path.join(root, '.ssh')); const userFile = path.join(root, '.ssh/known_hosts'); await fs.writeFile(userFile, 'person-owned'); + const file = path.join(directory, 'credentials.json'); + await fs.writeFile(file, JSON.stringify({ version: 1, profiles: [{ ...ssh, port: 2222 }, api] }), { mode: 0o600 }); + const before = await fs.stat(file), listed = (await store.list()).credentials; + assert.equal(listed[0].createdAt, before.mtime.toISOString()); assert.equal(listed[0].secretChangedAt, null); + assert.equal(listed[0].hostKey.fingerprint, carried.fingerprint); assert.equal(listed[0].hostKey.carried, true); + assert.equal(await fs.readFile(userFile, 'utf8'), 'person-owned'); + assert.equal(await fs.readFile(path.join(directory, 'known_hosts', ssh.id), 'utf8'), `${ssh.id} ${carried.type} ${carried.key}\n`); + assert.equal((await fs.stat(path.join(directory, 'known_hosts', ssh.id))).mode & 0o777, 0o600); + assert.deepEqual((await fs.readdir(directory)).sort(), ['credentials.json', 'known_hosts', 'state.json']); +}); + +test('migration failure leaves the exact v1 bytes and does not leave carried trust', async t => { + const key = credentialKey(); let breakStore = false; + const { store, io, directory } = await fixture(t, { effects: { ...fs, rename: async (a, b) => { if (breakStore && b.endsWith('/credentials.json')) { breakStore = false; throw new Error('injected failure'); } return fs.rename(a, b); } }, keys: { legacy: undefined, run: async () => ({ code: 0, stdout: 'old ' + key.type + ' ' + key.key }) } }); + await io.prepare(); const raw = JSON.stringify({ version: 1, profiles: [ssh] }); + await fs.writeFile(path.join(directory, 'credentials.json'), raw, { mode: 0o600 }); breakStore = true; + await assert.rejects(store.initialize(), { code: 'store' }); + assert.equal(await fs.readFile(path.join(directory, 'credentials.json'), 'utf8'), raw); + await assert.rejects(fs.stat(path.join(directory, 'known_hosts', ssh.id)), { code: 'ENOENT' }); + assert.equal((await store.list()).credentials[0].hostKey.carried, true, 'a repaired service can retry migration'); +}); + +test('helpers only read: no chmod, creation, migration, lock or state access', async t => { + const { directory, create, store, io } = await fixture(t); + const saved = (await create(api)).credential; + const before = await fs.readdir(directory); + const readOnly = createCredentialStore({ directory, readOnly: true }); + const modeBefore = (await fs.stat(path.join(directory, 'credentials.json'))).mode; + await fs.writeFile(path.join(directory, 'state.json'), '{invalid'); + assert.equal((await readOnly.forUse(api.id)).secret, api.secret); + assert.equal((await fs.stat(path.join(directory, 'credentials.json'))).mode, modeBefore); + assert.deepEqual((await fs.readdir(directory)).sort(), before.sort()); + await assert.rejects(readOnly.save({ credential: api, revision: saved.revision }), { code: 'read-only' }); + await fs.writeFile(path.join(directory, 'credentials.json'), JSON.stringify({ version: 1, profiles: [api] })); + await assert.rejects(readOnly.forUse(api.id), /Open Setup once/); + assert.equal(JSON.parse(await fs.readFile(path.join(directory, 'credentials.json'))).version, 1); + await store.initialize(); + await fs.chmod(path.join(directory, 'credentials.json'), 0o644); + await assert.rejects(readOnly.forUse(api.id)); + await store.list(); assert.equal((await fs.stat(path.join(directory, 'credentials.json'))).mode & 0o777, 0o600); + const missing = path.join(directory, 'absent'); + await assert.rejects(createCredentialStore({ directory: missing, readOnly: true }).forUse(api.id), { code: 'not-found' }); + await assert.rejects(fs.stat(missing), { code: 'ENOENT' }); +}); + +test('state damage is disposable and cannot confer or erase file-based host trust', async t => { + const { store, create, key, directory } = await fixture(t); + const a = (await create(ssh)).credential; + await store.trust({ id: a.id, revision: a.revision, key }); + const file = path.join(directory, 'state.json'); + await fs.writeFile(file, '{broken'); + const row = await store.public(a.id); + assert.equal(row.hostKey.fingerprint, key.fingerprint); assert.equal(row.hostKey.carried, false); assert.equal(row.test, null); + await store.recordTest({ id: a.id, revision: a.revision, hostFingerprint: key.fingerprint, result: { ok: true, code: 'ok', ms: 3, detail: { user: 'deploy', secret: ssh.secret } } }); + assert.equal((await store.public(a.id)).test.code, 'ok'); assert.equal(JSON.stringify(JSON.parse(await fs.readFile(file))).includes(ssh.secret), false); + await fs.rm(path.join(directory, 'known_hosts', a.id)); + assert.equal((await store.public(a.id)).hostKey, null); assert.equal((await store.forUse(a.id)).knownHostsFile, null); + assert.deepEqual((await store.summary()).attention, [{ id: a.id, code: 'host-key-untrusted' }]); +}); + +test('tests never bump revisions; late tests and removed trust never overwrite newer state', async t => { + const { store, create, key, directory } = await fixture(t); + let a = (await create(ssh)).credential; + await store.trust({ id: a.id, revision: a.revision, key }); + const before = await fs.readFile(path.join(directory, 'credentials.json'), 'utf8'); + const record = result => store.recordTest({ id: a.id, revision: a.revision, hostFingerprint: key.fingerprint, result: { ms: 3, detail: {}, ...result } }); + await record({ ok: false, code: 'timeout' }); assert.deepEqual((await store.summary()).attention, []); + await record({ ok: false, code: 'timeout' }); assert.equal((await store.summary()).attention[0].code, 'timeout'); + await record({ ok: true, code: 'ok' }); assert.deepEqual((await store.summary()).attention, []); + assert.equal(await fs.readFile(path.join(directory, 'credentials.json'), 'utf8'), before); + const old = a; a = (await store.save({ credential: { ...ssh, username: 'other', secret: '' }, revision: a.revision })).credential; + assert.equal(a.test, null); assert.equal(a.hostKey.fingerprint, key.fingerprint); + assert.equal(await store.recordTest({ id: a.id, revision: old.revision, hostFingerprint: key.fingerprint, result: { ok: true, code: 'ok' } }), false); + await store.forget(a.id); assert.equal(await record({ ok: true, code: 'ok' }), false); +}); + +test('host/port changes and deletion remove both metadata and the credential-specific key', async t => { + const { store, create, key, directory } = await fixture(t); + let a = (await create(ssh)).credential; + await store.trust({ id: a.id, revision: a.revision, key }); + const changed = await store.save({ credential: { ...ssh, port: 2222, secret: '' }, revision: a.revision }); + assert.equal(changed.credential.hostKey, null); + await assert.rejects(fs.stat(path.join(directory, 'known_hosts', a.id)), { code: 'ENOENT' }); + a = changed.credential; await store.trust({ id: a.id, revision: a.revision, key }); + const missingSecret = { ...a }; delete missingSecret.secret; + assert.equal((await store.draft({ id: a.id, draft: missingSecret })).knownHostsFile.endsWith('/' + a.id), true); + assert.equal((await store.draft({ id: a.id, draft: { ...missingSecret, host: 'other-host' } })).knownHostsFile, undefined); + await store.remove({ id: a.id, revision: a.revision }); + assert.equal(await store.recordTest({ id: a.id, revision: a.revision, result: { ok: true, code: 'ok' } }), false); + const metadata = JSON.parse(await fs.readFile(path.join(directory, 'state.json'))); + assert.deepEqual(metadata.tests, {}); assert.deepEqual(metadata.hostKeys, {}); + await assert.rejects(store.save({ credential: ssh, revision: a.revision }), { code: 'gone' }); +}); + +for (const damage of ['hardlink', 'symlink', 'oversize', 'fifo']) test('credential reads reject ' + damage + ' without touching its target', async t => { + const { store, create, directory, root } = await fixture(t); await create(api); + const file = path.join(directory, 'credentials.json'), external = path.join(root, 'external'); + await fs.rename(file, external); + if (damage === 'hardlink') await fs.link(external, file); + if (damage === 'symlink') await fs.symlink(external, file); + if (damage === 'oversize') await fs.writeFile(file, ' '.repeat(512 * 1024 + 1), { mode: 0o600 }); + if (damage === 'fifo') { const { execute } = await import('../docker/setup/credentials/hostkeys.mjs'); await execute('/usr/bin/mkfifo', [file]); } + const before = await fs.readFile(external, 'utf8'); + await assert.rejects(store.list()); + assert.equal(await fs.readFile(external, 'utf8'), before); +}); + +test('state recovery replaces its directory entry without following a symlink', async t => { + const { store, create, directory, root } = await fixture(t); const a = (await create(api)).credential; + const external = path.join(root, 'external'), file = path.join(directory, 'state.json'); + await fs.writeFile(external, 'keep this'); await fs.rm(file); await fs.symlink(external, file); + await store.recordTest({ id: a.id, revision: a.revision, result: { ok: false, code: 'failed', detail: { line: api.secret + ' and ' + Buffer.from(api.secret).toString('base64') } } }); + assert.equal(await fs.readFile(external, 'utf8'), 'keep this'); + assert.equal((await fs.lstat(file)).isSymbolicLink(), false); + assert.equal(JSON.stringify(await store.list()).includes(api.secret), false); +}); diff --git a/tests/credentials-usage.test.mjs b/tests/credentials-usage.test.mjs new file mode 100644 index 00000000..b94da5c2 --- /dev/null +++ b/tests/credentials-usage.test.mjs @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { credentialMentions, createCredentialUsage } from '../docker/setup/credentials/usage.mjs'; + +test('mentions honor quoted and unquoted names with exact command and name boundaries', () => { + assert.deepEqual([...credentialMentions(`t3-ssh build-server -- uptime\nt3-api 'project-api' GET me\n t3-api "another-key" GET me\n`) ], ['build-server', 'project-api', 'another-key']); + assert.deepEqual([...credentialMentions('not3-api nope\nx-t3-api nope\nt3-api Bad\nt3-api "quoted-mismatch\nt3-api missing-\nt3-api missing_\nt3-api foo-bar-baz2')], ['foo-bar-baz2']); +}); + +test('seven-provider scans deduplicate shared real files, include instructions and cache with invalidation', async t => { + const home = await fs.mkdtemp(path.join(os.tmpdir(), 'credential-usage-')); t.after(() => fs.rm(home, { recursive: true, force: true })); + const real = path.join(home, 'shared', 'deploy', 'SKILL.md'); await fs.mkdir(path.dirname(real), { recursive: true }); + await fs.writeFile(real, '---\nname: deploy\ndescription: Deploy from a shared skill.\n---\nt3-ssh build-server -- uptime'); + let scans = 0, reads = 0, at = 1000; + const usage = createCredentialUsage({ home, clock: () => at, installed: async () => ['claude', 'codex'], + scan: async provider => { scans++; return { skills: [{ path: real, resolvedPath: real }], warnings: provider === 'muse' ? ['limited'] : [] }; }, + readFile: async (file, limit, io) => { reads++; assert.equal(limit, 65536); return { content: await io.readFile(file, 'utf8'), bytes: 100 }; }, + instructions: async () => ({ content: 't3-api project-api GET me' }), + }); + const one = await usage.annotate([{ id: 'build-server' }, { id: 'project-api' }]); + assert.deepEqual(one.credentials[0].usedIn, [{ kind: 'skill', name: 'deploy', where: 'All agents' }]); + assert.deepEqual(one.credentials[1].usedIn, [{ kind: 'instructions', name: 'Global instructions' }]); + assert.equal(scans, 7); assert.equal(reads, 1); assert.equal(one.usageWarnings.length, 1); + await usage.annotate([]); assert.equal(scans, 7); + at += 16000; await usage.annotate([]); assert.equal(scans, 14); + usage.invalidate(); await usage.annotate([]); assert.equal(scans, 21); +}); + +test('failed and incomplete scans are visible instead of claiming a credential is unused', async () => { + const usage = createCredentialUsage({ scan: async provider => { if (provider === 'claude') throw new Error('unreadable'); return { skills: [{ path: '/unreadable', error: 'denied' }], warnings: [] }; }, instructions: async () => ({ error: 'denied' }) }); + const result = await usage.annotate([{ id: 'build-server' }]); assert.deepEqual(result.credentials[0].usedIn, []); assert.ok(result.usageWarnings.length >= 2); +}); diff --git a/tests/credentials.test.mjs b/tests/credentials.test.mjs index 2227e379..d623a303 100644 --- a/tests/credentials.test.mjs +++ b/tests/credentials.test.mjs @@ -17,47 +17,47 @@ async function fixture(t) { t.after(() => fs.rm(root, { recursive: true, force: true })); return { root, directory, store: createCredentialStore({ directory }) }; } -const create = async (store, profile) => store.save({ profile, revision: (await store.list()).revision, create: true }); +const create = async (store, profile) => store.save({ credential: profile, create: true }); test('credentials persist privately and public reads never include saved values', async t => { const { directory, store } = await fixture(t); await create(store, ssh); await create(store, { id: 'project-api', label: 'Project API', type: 'api', baseUrl: 'http://192.0.2.2/api', secret: secret + '-token' }); const snapshot = await createCredentialStore({ directory }).list(); - assert.equal(snapshot.profiles.length, 2); - assert.equal(snapshot.profiles[1].baseUrl, 'http://192.0.2.2/api/'); + assert.equal(snapshot.credentials.length, 2); + assert.equal(snapshot.credentials[1].baseUrl, 'http://192.0.2.2/api/'); assert.equal(JSON.stringify(snapshot).includes(secret), false); assert.equal((await store.forUse('build-server')).secret, secret); assert.equal((await fs.stat(directory)).mode & 0o777, 0o700); assert.equal((await fs.stat(path.join(directory, 'credentials.json'))).mode & 0o777, 0o600); - const saved = await store.save({ profile: { ...ssh, secret: '', label: 'Renamed' }, revision: snapshot.revision }); + const before = snapshot.credentials.find(row => row.id === 'build-server'); + const saved = await store.save({ credential: { ...ssh, secret: '' }, revision: before.revision }); assert.equal((await store.forUse('build-server')).secret, secret); assert.equal(JSON.stringify(saved).includes(secret), false); - await store.save({ profile: { ...ssh, secret: 'replacement-password' }, revision: saved.revision }); + const next = await store.save({ credential: { ...ssh, secret: 'replacement-password' }, revision: saved.credential.revision }); assert.equal((await store.forUse('build-server')).secret, 'replacement-password'); - await store.remove({ id: 'build-server', revision: (await store.list()).revision }); + await store.remove({ id: 'build-server', revision: next.credential.revision }); await assert.rejects(store.forUse('build-server'), /not found/); - assert.equal((await store.list()).profiles.length, 1); + assert.equal((await store.list()).credentials.length, 1); }); test('conflicting, duplicate and overlapping writes cannot overwrite another editor', async t => { - const { store } = await fixture(t); - const before = await store.list(); - await create(store, ssh); - await assert.rejects(store.save({ profile: { ...ssh, secret: 'lost' }, revision: before.revision }), { status: 409 }); - let revision = (await store.list()).revision; - await assert.rejects(store.save({ profile: ssh, revision, create: true }), { status: 409 }); - const outcomes = await Promise.allSettled(['First', 'Second'].map(label => store.save({ profile: { ...ssh, label }, revision }))); + const { store, directory } = await fixture(t); + const initial = (await create(store, ssh)).credential; + await assert.rejects(create(store, ssh), { status: 409, code: 'taken' }); + const other = createCredentialStore({ directory }); + const outcomes = await Promise.allSettled(['first-host', 'second-host'].map((host, index) => (index ? other : store).save({ credential: { ...ssh, host }, revision: initial.revision }))); assert.deepEqual(outcomes.map(outcome => outcome.status), ['fulfilled', 'rejected']); assert.equal(outcomes[1].reason.status, 409); - revision = (await store.list()).revision; - await assert.rejects(store.remove({ id: 'build-server', revision: before.revision }), { status: 409 }); - assert.equal((await store.forUse('build-server')).label, 'First'); + assert.equal(outcomes[1].reason.code, 'changed'); + assert.equal(JSON.stringify(credentialFailure(outcomes[1].reason)).includes(secret), false); + await assert.rejects(store.remove({ id: 'build-server', revision: initial.revision }), { status: 409, code: 'changed' }); + assert.equal((await store.forUse('build-server')).host, 'first-host'); }); test('invalid input and damaged stores fail without echoing or replacing credentials', async t => { const { directory, root, store } = await fixture(t); - for (const change of [{ id: '../escape' }, { host: '-oProxyCommand=bad' }, { username: 'user;bad' }, { port: 0 }, { secret: 'line\nbreak' }, { secret: '\ud800' }, { secret: undefined }, { label: '\u0000' }, { type: 'unknown' }]) { + for (const change of [{ id: '../escape' }, { host: '-oProxyCommand=bad' }, { username: 'user;bad' }, { port: 0 }, { secret: 'line\nbreak' }, { secret: '\ud800' }, { secret: undefined }, { type: 'unknown' }]) { await assert.rejects(create(store, { ...ssh, ...change })); } for (const baseUrl of ['file:///etc/passwd', 'https://user:password@example.com', 'http://example.com?secret=hello', 'http://example.com/#secret']) { @@ -99,12 +99,12 @@ test('legacy bearer connections remain readable and changing auth settings retai const legacy = JSON.stringify({ version: 1, profiles: [{ id: 'service', label: 'Service API', type: 'api', baseUrl: 'https://api.example.com/v1/', secret }] }); await fs.writeFile(file, legacy, { mode: 0o600 }); assert.equal((await store.forUse('service')).authType, 'bearer'); - assert.equal(await fs.readFile(file, 'utf8'), legacy); + assert.equal(JSON.parse(await fs.readFile(file, 'utf8')).version, 2); const before = await store.list(); - const saved = await store.save({ profile: { ...before.profiles[0], authType: 'header', authName: 'X-API-Key', authPrefix: '', testPath: 'account', secret: '' }, revision: before.revision }); + const saved = await store.save({ credential: { ...before.credentials[0], authType: 'header', authName: 'X-API-Key', authPrefix: '', testPath: 'account', secret: '' }, revision: before.credentials[0].revision }); assert.equal(JSON.stringify(saved).includes(secret), false); assert.equal((await store.forUse('service')).secret, secret); - assert.equal((await store.list()).profiles[0].authName, 'X-API-Key'); + assert.equal((await store.list()).credentials[0].authName, 'X-API-Key'); }); test('API authentication and test-path validation rejects unsafe configuration', async t => { @@ -130,7 +130,7 @@ for (const [authType, authName, authPrefix] of [['bearer', undefined, undefined] await create(store, { id: 'service', label: 'Service API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/v1/', secret: key, authType, authName, authPrefix, testPath: 'account' }); const profile = await store.forUse('service'); - assert.equal(await testCredential(profile), 0); + assert.equal((await testCredential(profile)).code, 'ok'); assert.equal(received.url.pathname, '/v1/account'); if (authType === 'query') { assert.equal(received.url.searchParams.get(authName), key); assert.equal(received.headers.authorization, undefined); } else assert.equal(received.headers[(authName || 'authorization').toLowerCase()], (authType === 'bearer' ? 'Bearer ' : authPrefix ? authPrefix + ' ' : '') + key); @@ -158,12 +158,12 @@ test('API helper authenticates internally, filters output and never follows redi assert.equal(await apiRequest(profile, 'POST', 'projects', { body: '{"name":"demo-project"}', stdout: { write: text => { output += text; } } }), 0); assert.equal(output, 'hello [redacted] goodbye'); assert.deepEqual(received, { url: '/api/projects', method: 'POST', body: '{"name":"demo-project"}' }); - await assert.rejects(apiRequest(profile, 'GET', 'redirect'), /redirects are not followed/); + await assert.rejects(apiRequest(profile, 'GET', 'redirect'), /redirect/); assert.equal(calls, 2, 'redirect destination was never requested'); - await assert.rejects(apiRequest(profile, 'GET', 'unauthorized', { probe: true }), error => !error.message.includes(secret) && /HTTP 401/.test(error.message)); - assert.equal(await testCredential(profile), 0); + assert.deepEqual(await apiRequest(profile, 'GET', 'unauthorized', { probe: true }), { ok: false, code: 'rejected', detail: { status: 401 } }); + assert.equal((await testCredential(profile)).code, 'ok'); const cancelled = new AbortController(); cancelled.abort(); - await assert.rejects(testCredential(profile, { signal: cancelled.signal }), /API request failed/); + assert.equal((await testCredential(profile, { signal: cancelled.signal })).code, 'timeout'); for (const target of ['https://other.test/api', '//other.test', '/api/states', '../outside', '%2e%2e/outside', 'foo\\outside', '#fragment']) assert.throws(() => apiTarget(profile, target)); }); @@ -177,9 +177,9 @@ process.stdout.write('output '+secret.slice(0,5)); process.stderr.write('error '+secret.slice(0,5)); setTimeout(()=>{process.stdout.write(secret.slice(5)+' done');process.stderr.write(secret.slice(5)+' done');},10);`); let out = '', err = ''; - const code = await sshRequest(ssh, ['uptime'], { stdin: 'ignore', stdout: { write: value => { out += value; } }, stderr: { write: value => { err += value; } }, + const code = await sshRequest({ ...ssh, knownHostsFile: '/synthetic/known_hosts/build-server', hostKeyType: 'ssh-ed25519' }, ['uptime'], { stdin: 'ignore', stdout: { write: value => { out += value; } }, stderr: { write: value => { err += value; } }, spawnProcess: (executable, args, options) => { - assert.equal(executable, '/usr/bin/ssh'); assert.ok(args.includes('StrictHostKeyChecking=accept-new')); + assert.equal(executable, '/usr/bin/ssh'); assert.ok(args.includes('StrictHostKeyChecking=yes')); assert.equal(JSON.stringify(args).includes(secret), false); assert.deepEqual(args.slice(-2), ['192.0.2.1', 'uptime']); return spawn(process.execPath, [fixtureFile], options); @@ -188,7 +188,7 @@ setTimeout(()=>{process.stdout.write(secret.slice(5)+' done');process.stderr.wri assert.equal(code, 0); assert.equal(out, 'output [redacted] done'); assert.equal(err, 'error [redacted] done'); const controller = new AbortController(); let interrupted; t.after(() => interrupted?.kill()); - await assert.rejects(sshRequest(ssh, ['true'], { stdin: 'ignore', signal: controller.signal, + await assert.rejects(sshRequest({ ...ssh, knownHostsFile: '/synthetic/known_hosts/build-server', hostKeyType: 'ssh-ed25519' }, ['true'], { stdin: 'ignore', signal: controller.signal, spawnProcess: (_executable, _args, options) => { interrupted = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], options); interrupted.once('spawn', () => controller.abort()); @@ -196,7 +196,7 @@ setTimeout(()=>{process.stdout.write(secret.slice(5)+' done');process.stderr.wri }, }), /SSH could not start or was interrupted/); if (interrupted.signalCode === null && interrupted.exitCode === null) await once(interrupted, 'close'); - assert.equal(interrupted.signalCode, 'SIGTERM'); + assert.equal(interrupted.signalCode, 'SIGKILL'); }); test('SSH hosts accept IPv6 addresses including leading ::', async t => { diff --git a/tests/fixtures/credential-keys.mjs b/tests/fixtures/credential-keys.mjs new file mode 100644 index 00000000..dd9cad2e --- /dev/null +++ b/tests/fixtures/credential-keys.mjs @@ -0,0 +1,7 @@ +import { randomBytes, createHash } from 'node:crypto'; +export function credentialKey() { + const type = 'ssh-ed25519', name = Buffer.from(type), length = Buffer.alloc(4), keyLength = Buffer.alloc(4); + length.writeUInt32BE(name.length); keyLength.writeUInt32BE(32); + const wire = Buffer.concat([length, name, keyLength, randomBytes(32)]); + return { type, key: wire.toString('base64'), fingerprint: 'SHA256:' + createHash('sha256').update(wire).digest('base64').replace(/=+$/, '') }; +} From 6ee10335ea952027777b2a90a3f09b4a81921b2f Mon Sep 17 00:00:00 2001 From: Ziyang Zeng Date: Sat, 31 Oct 2026 04:11:54 +0000 Subject: [PATCH 7/8] feat(credentials): redesign login management and recovery flows --- docker/setup/app.js | 12 +- docker/setup/client/credential-dialogs.js | 78 +++++ docker/setup/client/credential-editor.js | 155 +++++++++ docker/setup/client/credential-inspector.js | 58 ++++ docker/setup/client/credential-model.js | 78 +++++ docker/setup/client/credentials.js | 233 +++++++------ docker/setup/client/model.js | 41 ++- docker/setup/client/routes.js | 4 +- docker/setup/console.css | 287 ++++++++++++++-- docker/setup/credentials.mjs | 2 +- docker/setup/credentials/service.mjs | 5 +- docker/setup/page.mjs | 4 + docker/setup/server.mjs | 4 +- docker/t3-client/setup-bridge.js | 1 + scripts/console-preview.mjs | 5 +- scripts/credentials-ui-audit.mjs | 349 +++++++++++++------- scripts/credentials-visual-audit.mjs | 72 ++++ scripts/fixtures/console/credentials.json | 164 ++++++++- scripts/lib/credentials-fixtures.cjs | 62 ++++ scripts/setup-tab-audit.js | 4 +- scripts/smoke-test.sh | 16 + tests/credential-model.test.mjs | 35 ++ tests/credentials-service.test.mjs | 9 + tests/credentials-store.test.mjs | 7 + tests/fixtures/standalone-shell.html | 4 +- tests/navigation-model.test.mjs | 6 + 26 files changed, 1410 insertions(+), 285 deletions(-) create mode 100644 docker/setup/client/credential-dialogs.js create mode 100644 docker/setup/client/credential-editor.js create mode 100644 docker/setup/client/credential-inspector.js create mode 100644 docker/setup/client/credential-model.js create mode 100644 scripts/credentials-visual-audit.mjs create mode 100644 scripts/lib/credentials-fixtures.cjs create mode 100644 tests/credential-model.test.mjs diff --git a/docker/setup/app.js b/docker/setup/app.js index a41eb335..6d1f5d3f 100644 --- a/docker/setup/app.js +++ b/docker/setup/app.js @@ -154,7 +154,7 @@ const skillsUI = T3SkillsUI.create({ api, getStatus: () => state.status, render: () => render(), readMarkdown: (file) => readMarkdownFile(file, 64 * 1024), downloadMarkdown: (...args) => downloadMarkdown(...args) }); const mcpUI = T3McpUI.create({ api, getStatus: () => state.status, render: () => render() }); - const credentialsUI = T3CredentialsUI.create({ api, render: () => render() }); + const credentialsUI = T3CredentialsUI.create({ api, getStatus: () => state.status, render: () => render(), onChange: () => loadStatus(true) }); const filesUI = T3FilesUI.create({ api, base: BASE, getStatus: () => state.status, getRoute: () => state.route, render: () => render(), go: route => go(route) }); /** Whether this browser came in on its T3 Code session rather than the key, so Lock would end nothing. */ @@ -215,8 +215,9 @@ } }; - const loadStatus = () => { - if (statusLoading) return statusLoading; + const loadStatus = (fresh = false) => { + // A completed mutation must read after an older poll, not join its snapshot. + if (statusLoading) return fresh === true ? statusLoading.then(() => loadStatus()) : statusLoading; statusLoading = (async () => { const accessRevision = access.revision; const res = await api('/status'); @@ -2000,6 +2001,7 @@ if (contextEditor.layer && !await contextEditor.requestClose()) return false; if (!await skillsUI.beforeNavigate()) return false; if (!await mcpUI.beforeNavigate()) return false; + if (!await credentialsUI.beforeNavigate()) return false; return filesUI.beforeNavigate(); }; let hostLeaving = false; @@ -4089,7 +4091,7 @@ // -------------------------------------------------------------- palette -- const openPalette = () => { const layer = Kit.palette({ - items: () => [...M.paletteItems(state.status || {}, state.ports, ui, now()), ...skillsUI.paletteItems().map(item => ({ ...item, group: 'Instructions & skills', keywords: item.desc || '' })), ...filesUI.paletteItems()], + items: () => [...M.paletteItems(state.status || {}, state.ports, ui, now()), ...skillsUI.paletteItems().map(item => ({ ...item, group: 'Instructions & skills', keywords: item.desc || '' })), ...filesUI.paletteItems(), ...credentialsUI.paletteItems()], search: M.searchPalette, run: (item) => { const { cmd, ...args } = item.cmd; @@ -4104,7 +4106,7 @@ // ------------------------------------------------------------ shortcuts -- Kit.bind('mod+k', openPalette); - Kit.bind('/', () => state.route === 'files' ? filesUI.focusSearch() : state.route === 'mcp' ? mcpUI.focusSearch() : state.route === 'instructions' && state.contextTab === 'skills' ? skillsUI.focusSearch() : openPalette()); + Kit.bind('/', () => state.route === 'files' ? filesUI.focusSearch() : state.route === 'mcp' ? mcpUI.focusSearch() : state.route === 'credentials' ? credentialsUI.focusSearch() : state.route === 'instructions' && state.contextTab === 'skills' ? skillsUI.focusSearch() : openPalette()); for (const page of T3Routes.PAGES) { if (page.key) Kit.bind('g ' + page.key, () => { keyboardNav = true; go(page.route); }); } diff --git a/docker/setup/client/credential-dialogs.js b/docker/setup/client/credential-dialogs.js new file mode 100644 index 00000000..c0f091f7 --- /dev/null +++ b/docker/setup/client/credential-dialogs.js @@ -0,0 +1,78 @@ +const T3CredentialDialogs = (() => { + 'use strict'; + const { html, raw, icon } = Kit, S = T3CredentialModel, M = T3Model; + const disabled = value => value ? raw(' disabled') : ''; + const create = ctx => { + let active = null; + const removing = new Set(); + const remove = async id => { + const profile = ctx.row(id); if (!profile || ctx.busy.has(id) || removing.has(id)) return; + removing.add(id); + try { + const yes = await Kit.confirm({ title: 'Delete ' + id + '?', body: html`Skills that call ${(profile.type === 'ssh' ? 't3-ssh ' : 't3-api ') + id} fail until a credential with this name exists again.`, + consequences: [ + { icon: 'book-open', text: profile.usedIn?.length ? 'Mentioned in ' + M.listOf(profile.usedIn.map(item => item.name)) : ctx.usageWarnings()?.length ? 'Some skills couldn’t be read; there may be mentions.' : 'Not used in a skill' }, + ...(ctx.usageWarnings()?.length && profile.usedIn?.length ? [{ icon: 'info', text: 'Some skills couldn’t be read; there may be other mentions.' }] : []), + { icon: 'key-round', text: 'The saved ' + S.secretKind(profile) + ' is erased from this server' }, + { icon: 'archive', text: 'Backups of this volume still hold it' }, + ...(profile.type === 'ssh' ? [{ icon: 'shield-alert', text: 'Its trusted host key is forgotten' }] : []), + ], confirm: 'Delete credential', tone: 'danger' }); + if (!yes) return; + const response = await ctx.request(id, 'remove', '/credentials/remove', { id, revision: profile.revision }); + if (response?.ok) { ctx.deleted(id); Kit.toast(id + ' deleted'); } + else if (response) Kit.toast('Couldn’t delete ' + id, { tone: 'danger', detail: response.error }); + } finally { removing.delete(id); } + }; + const forget = async id => { + if (ctx.busy.has(id)) return; + const yes = await Kit.confirm({ title: 'Forget ' + id + '’s host key?', body: 'Agents will be blocked from connecting until you review and trust the server’s key again.', confirm: 'Forget host key', tone: 'danger' }); + if (!yes) return; + const response = await ctx.request(id, 'forget', '/credentials/forget-host-key', { id }); + if (response?.ok) Kit.toast('Forgot ' + id + '’s host key'); + }; + const review = async id => { + let profile = ctx.row(id); if (!profile || ctx.busy.has(id) || active) return; + const view = { id, busy: false, scanned: null, error: null, changedAgain: false, stale: false }; active = view; + const close = reason => { if (view.busy) { Kit.announce('Wait for the host-key check to finish.'); return false; } view.layer.close(reason); return true; }; + const changed = () => view.scanned?.state === 'changed'; + const paint = () => { if (active === view) view.layer.render(); }; + const scan = async () => { + if (view.busy) return; + const current = ctx.row(id); if (current) profile = current; + view.scanned = null; view.stale = false; view.changedAgain = false; view.busy = true; view.error = null; paint(); + const response = await ctx.request(id, 'scan', '/credentials/scan', { id, revision: profile.revision }, { refresh: false }); + if (active !== view) return; + view.busy = false; + if (['changed', 'gone', 'not-found'].includes(response?.data?.code)) { view.stale = true; view.error = 'The saved connection details changed. Review the current host before trusting a key.'; } + else if (!response?.ok || !response.data.hostKey) view.error = response?.data?.result ? S.state({ ...profile, hostKey: profile.hostKey || {}, test: response.data.result }).desc : response?.error || 'Couldn’t read this server’s host key. Try again.'; + else view.scanned = response.data.hostKey; + paint(); view.layer.panel.querySelector('[data-cred-key="cancel"]')?.focus({ preventScroll: true }); + }; + view.layer = Kit.open({ kind: 'center', backdrop: 'ignore', panel: { class: 'tc-dialog tc-cred-dialog', role: 'alertdialog', 'aria-modal': 'true', 'aria-labelledby': 'cred-key-title', 'aria-describedby': 'cred-key-desc' }, focus: '[data-cred-key="cancel"]', onEscape: () => close('escape'), onClose: () => { if (active === view) active = null; }, render: () => html` +

${changed() ? id + '’s host key changed' : 'Trust ' + profile.host + '’s host key?'}

${changed() ? profile.host + ' now presents a different key. That’s expected after a reinstall, and also what an interception looks like. Agents can’t connect until you decide.' : 'Compare this fingerprint with the server’s own key before trusting it. No password is sent while the key is being checked.'}

+ ${view.busy ? html`

${view.scanned ? 'Checking the key again before trusting it…' : 'Reading the server’s host key…'}

` : ''} + ${view.scanned ? html`
    ${view.scanned.trusted ? html`
  • Trusted ${profile.hostKey?.trustedAt ? S.day(profile.hostKey.trustedAt) : 'before'}${S.keyType(view.scanned.trusted.type)}
    ${view.scanned.trusted.fingerprint}
  • ` : ''}
  • Presented now${S.keyType(view.scanned.presented.type)}
    ${view.scanned.presented.fingerprint}

On the server, this prints its real key:

  • ${S.keyCommand(view.scanned.presented.type)}
` : ''} + ${view.error ? html`` : ''}${view.changedAgain ? html`` : ''}
+
${view.error && (!view.scanned || view.stale) ? html`` : html``}
` }); + view.layer.panel.addEventListener('click', async event => { + const button = event.target.closest('[data-cred-key]'); if (!button || button.disabled) return; + const action = button.dataset.credKey; + if (action === 'cancel') return close('cancel'); + if (action === 'copy') return void Kit.copy(S.keyCommand(view.scanned.presented.type), button); + if (action === 'retry') { await ctx.refresh(); return void scan(); } + if (action !== 'trust' || view.busy || !view.scanned) return; + view.busy = true; view.error = null; view.changedAgain = false; paint(); + const response = await ctx.request(id, 'trust', '/credentials/trust', { id, revision: profile.revision, fingerprint: view.scanned.presented.fingerprint }); + if (active !== view) return; view.busy = false; + if (response?.ok) { view.layer.close('trusted'); Kit.toast(id + '’s host key trusted'); return; } + if (['changed', 'gone', 'not-found'].includes(response?.data?.code)) { view.stale = true; view.error = 'The saved connection details changed. Review the current host before trusting a key.'; } + else if (response?.data?.code === 'key-changed' && response.data.presented) { view.scanned = { ...view.scanned, state: 'changed', presented: response.data.presented }; view.changedAgain = true; } + else view.error = response?.error || 'The host key could not be trusted. Try again.'; + paint(); (view.layer.panel.querySelector('#cred-key-error') || view.layer.panel.querySelector('[data-cred-key="cancel"]'))?.focus({ preventScroll: true }); + }); + await scan(); + }; + return { remove, forget, review, beforeNavigate: () => !active?.busy }; + }; + return { create }; +})(); diff --git a/docker/setup/client/credential-editor.js b/docker/setup/client/credential-editor.js new file mode 100644 index 00000000..b1ba4458 --- /dev/null +++ b/docker/setup/client/credential-editor.js @@ -0,0 +1,155 @@ +// Drafts own their input subtree. Only a newly typed secret lives here; neither +// saved values nor server responses are copied into the form or a preview. +const T3CredentialEditor = (() => { + 'use strict'; + const { html, raw, icon } = Kit, S = T3CredentialModel, M = T3Model; + const disabled = value => value ? raw(' disabled') : ''; + const checked = value => value ? raw(' checked') : ''; + const create = ctx => { + let active = null; + const close = reason => active ? active.close(reason) : Promise.resolve(true); + const open = async (profile, { replace = false } = {}) => { + if (!await close('replaced')) return; + const view = { original: profile || null, draft: S.draftOf(profile), revision: profile?.revision, create: !profile, secret: '', replacing: !profile || replace, + touched: new Set(), busy: null, error: null, conflict: null, taken: false, result: null, scanned: null, trusted: false, revealed: false, railOpen: false, generation: 0, closing: false }; + active = view; + const baseline = () => JSON.stringify(S.payload(view.original ? S.draftOf(view.original) : S.defaults('ssh'))); + const dirty = () => Boolean(view.secret || view.trusted || JSON.stringify(S.payload(view.draft)) !== baseline()); + const errors = () => ({ ...S.validate(view.draft, { editing: !view.create, names: ctx.rows().filter(row => row.id !== view.recreateId).map(row => row.id), secret: view.secret, hasSecret: !view.create && view.original?.hasSecret }), ...(view.taken ? { id: view.draft.id + ' is taken.' } : {}) }); + const valid = () => !Object.keys(errors()).length; + const canSave = () => !view.busy && valid() && (!view.original || dirty()) && !view.conflict; + const sync = () => { + for (const input of view.layer.panel.querySelectorAll('[data-cred-field]')) { + const key = input.dataset.credField, value = key === 'secret' ? view.secret : view.draft[key]; + if (input.value !== String(value ?? '')) input.value = value ?? ''; + } + const trust = view.layer.panel.querySelector('[data-cred-editor="trust"]'); if (trust) trust.checked = view.trusted; + view.layer.panel.querySelector('.tc-wizard-rail-wrap')?.toggleAttribute('data-open', !Kit.isPhone() || view.railOpen); + }; + const paint = () => { if (active !== view || view.layer?.closed) return; view.layer.render(); sync(); }; + view.repaint = paint; + view.close = async reason => { + if (view.busy || view.closing) { Kit.announce('Wait for this credential check or save to finish.'); return false; } + if (dirty()) { + view.closing = true; + const yes = await Kit.confirm({ title: 'Discard changes?', body: 'Your credential changes have not been saved.', confirm: 'Discard changes', tone: 'danger' }); + view.closing = false; if (!yes || active !== view) return false; + } + view.layer.close(reason); return true; + }; + const beforeUnload = event => { if (view.busy || dirty()) { event.preventDefault(); event.returnValue = ''; } }; + window.addEventListener('beforeunload', beforeUnload); + const hint = (key, fallback) => { + const error = view.touched.has(key) && errors()[key]; + return html`${fallback ? html`

${fallback}

` : ''}${error ? html`` : ''}`; + }; + const input = (key, label, options = {}) => { + const invalid = view.touched.has(key) && Boolean(errors()[key]); + return html`
${hint(key, options.hint)}
`; + }; + const secret = () => html`
${view.replacing ? html`` : html`${view.draft.type === 'ssh' ? 'Password' : 'API key'}`}${!view.replacing && view.original ? html`
${icon('circle-check')}Saved ${view.original.secretChangedAt ? '· changed ' + S.day(view.original.secretChangedAt) : '· from before the upgrade'}
` : html`
`}${hint('secret', view.original ? 'Leaving the replacement empty keeps the saved ' + S.secretKind(view.draft) + '.' : view.draft.type === 'ssh' ? 'Not shown again after you save. Key-based sign-in isn’t supported yet.' : 'Not shown again after you save. Agents use the credential’s name.')}${view.original && view.replacing ? html`` : ''}
`; + const segment = (key, label, choices) => html`
${label}
${choices.map(([value, title, mark]) => html``)}
`; + const fields = () => html`
${view.create ? segment('type', 'Type', [['ssh', 'SSH server', 'terminal'], ['api', 'HTTP API', 'globe']]) : ''}${view.create ? input('id', 'Name', { max: 64, hint: Kit.isPhone() ? 'Skills use it, so it can’t change later.' : 'Lowercase letters, numbers and hyphens. Skills use it, so it can’t change later.' }) : html`
Name
${icon('lock')}${view.draft.id}Can’t change

${ctx.usageWarnings()?.length ? 'Some skills couldn’t be read.' : 'Mentioned in ' + S.usageCount(view.original) + '.'}

`} + ${view.draft.type === 'ssh' ? html`
${input('host', 'Host', { max: 253, placeholder: '192.0.2.10' })}${input('port', 'Port', { type: 'number' })}
${input('username', 'Username', { max: 64, placeholder: 'deploy' })}` : html`${input('baseUrl', 'Base URL', { max: 2048, placeholder: 'https://api.example.com/v1/', hint: 'Include the version or base path. Requests can’t leave it.' })}${segment('authType', 'Authentication', [['bearer', 'Bearer token'], ['header', 'Header'], ['query', 'Query parameter']])}${view.draft.authType === 'header' ? html`
${input('authName', 'Header name', { max: 128, placeholder: 'X-API-Key' })}${input('authPrefix', 'Value prefix (optional)', { max: 128, placeholder: 'None' })}
` : view.draft.authType === 'query' ? input('authName', 'Parameter name', { max: 128, placeholder: 'api_key', hint: 'Prefer a header when the service supports one: query keys can appear in its logs.' }) : ''}`}${secret()}
`; + const result = () => { + const profile = { ...view.draft, hostKey: view.scanned && view.trusted ? view.scanned.presented : view.original?.hostKey || (view.result ? {} : null), test: view.result }; + const state = view.result ? S.state(profile) : null, key = view.scanned?.presented; + return html`
${view.busy === 'test' ? html`

Testing…

` : ''}${key ? html`
${view.scanned.state === 'changed' ? 'Different host key from ' : 'First connection to '}${view.draft.host}${S.keyType(key.type)} ${key.fingerprint}${Kit.isPhone() ? html`
Compare with the server’s key${S.keyCommand(key.type)}
` : html`Compare it with the server’s own:${S.keyCommand(key.type)}`}
` : ''}${state && !['host-key-untrusted', 'host-key-changed'].includes(state.code) ? html`
${icon(state.icon || 'info')}${view.result.ok && view.draft.type === 'ssh' ? 'Signed in as ' + view.draft.username : state.label}${view.result.ms >= 1000 ? (view.result.ms / 1000).toFixed(1) + ' s' : view.result.ms + ' ms'}
${!view.result.ok ? html`

${state.desc}

` : ''}` : !key && view.busy !== 'test' ? html`

Test the login before saving it. Nothing is saved by a draft test.

` : ''}${view.result?.code === 'host-key-changed' && !view.trusted ? html`` : ''}
`; + }; + const testButton = (phone = false) => html``; + const testSection = () => html`

Test before saving${Kit.isPhone() ? '' : testButton()}

${view.draft.type === 'api' ? html`${input('testPath', 'GET test path (optional)', { max: 2048, placeholder: 'account', hint: 'Pick an endpoint that needs the key: a public one answers without it. Blank tests the base URL.' })}` : ''}${result()}
`; + const rail = () => html`
Agents run ${(view.draft.type === 'ssh' ? 't3-ssh ' : 't3-api ') + (view.draft.id || 'name')}${icon('chevron-down')}
`; + const conflict = () => !view.conflict ? '' : html``; + const submit = async () => { + if (view.busy || active !== view || view.conflict) return; + if (!valid()) { Object.keys(errors()).forEach(key => view.touched.add(key)); paint(); view.layer.panel.querySelector('[aria-invalid="true"]')?.focus(); return; } + if (view.original && !dirty()) return; + view.busy = 'save'; view.error = null; paint(); + const credential = { ...S.payload(view.draft), ...(view.secret ? { secret: view.secret } : {}) }; + const response = await ctx.api(view.create ? '/credentials/create' : '/credentials/save', { body: { credential, ...(!view.create ? { revision: view.revision } : {}), ...(view.trusted && view.scanned ? { trust: { fingerprint: view.scanned.presented.fingerprint } } : {}) } }); + delete credential.secret; + if (active !== view) return; + if (!response.ok) { + view.busy = null; + if (['changed', 'gone'].includes(response.data?.code)) view.conflict = response.data; + else if (response.data?.code === 'taken') { view.taken = true; view.touched.add('id'); } + else view.error = response.error || 'Couldn’t save this credential. Your draft is still here.'; + paint(); (view.layer.panel.querySelector('#cred-conflict, #cred-editor-error') || view.layer.panel.querySelector('[aria-invalid="true"]'))?.focus({ preventScroll: true }); return; + } + const id = view.draft.id, failedTrust = response.data.trust?.ok === false; + const refreshed = await ctx.saved(response.data.credential); + if (active !== view) return; + view.busy = null; view.layer.close('saved'); + Kit.toast(id + ' saved', !refreshed ? { tone: 'warn', detail: 'Saved, but the list could not be refreshed. Try again on the Credentials page.' } : failedTrust ? { tone: 'warn', detail: 'Its host key could not be trusted. Review it before agents connect.', action: { label: 'Review', run: () => ctx.review(id) } } : undefined); + }; + const test = async () => { + if (view.busy || !valid()) return; + view.busy = 'test'; view.error = null; const generation = ++view.generation; paint(); + const draft = { ...S.payload(view.draft), ...(view.secret ? { secret: view.secret } : {}) }; + const response = await ctx.api('/credentials/test', { body: { draft, ...(!view.create ? { id: view.draft.id } : {}), ...(view.trusted && view.scanned ? { trust: { fingerprint: view.scanned.presented.fingerprint } } : {}) } }); + delete draft.secret; + if (active !== view || generation !== view.generation) return; + view.busy = null; + if (!response.ok || !response.data.result) view.error = response.error || 'The test could not finish. Your draft is still here.'; + else { + view.result = response.data.result; + if (view.result.hostKey) { view.scanned = view.result.hostKey; view.trusted = false; } + else if (view.result.code === 'host-key-changed' && view.result.detail?.presented) { view.scanned = { state: 'changed', presented: view.result.detail.presented, trusted: view.result.detail.trusted }; view.trusted = false; } + Kit.announce(view.result.ok ? 'Connection succeeded. This draft is not saved yet.' : S.state({ ...view.draft, hostKey: view.original?.hostKey, test: view.result }).label); + } + paint(); + if (Kit.isPhone()) (view.layer.panel.querySelector(view.error ? '#cred-editor-error' : '.tc-cred-test-line') || view.layer.panel.querySelector('.tc-cred-hostkey--first'))?.scrollIntoView({ block: 'nearest' }); + }; + view.layer = Kit.open({ kind: 'center', backdrop: 'ignore', panel: { tag: 'form', class: 'tc-wizard tc-cred-editor', role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'cred-editor-title', autocomplete: 'off', novalidate: true }, focus: replace ? '#cred-secret' : profile ? '#cred-host, #cred-baseUrl' : '#cred-id', onEscape: () => { void view.close('escape'); }, onClose: () => { + view.generation++; view.secret = ''; view.revealed = false; + const secret = view.layer.panel.querySelector('#cred-secret'); if (secret) { secret.value = ''; secret.type = 'password'; } + window.removeEventListener('beforeunload', beforeUnload); if (active === view) active = null; + }, render: () => html`

${view.create ? 'Add credential' : 'Edit ' + view.draft.id}

${view.create ? 'Save a login once. Agents use it by name.' : (view.draft.type === 'ssh' ? 'SSH server' : 'HTTP API') + ' · ' + (view.original.usedIn?.length ? 'used in ' + M.listOf(view.original.usedIn.map(item => item.name)) : ctx.usageWarnings()?.length ? 'usage partly checked' : 'not in a skill yet')}
${conflict()}${fields()}${Kit.isPhone() ? testSection() : ''}
${rail()}
${view.error ? html`` : ''}
${icon('lock', 'tc-icon--sm')}Saved on this server, in plain text.${Kit.isPhone() ? html`${testButton(true)}` : html``}
` }); + sync(); + view.layer.panel.addEventListener('submit', event => { event.preventDefault(); void submit(); }); + view.layer.panel.addEventListener('input', event => { + const key = event.target.dataset.credField; if (!key || view.busy) return; + if (key === 'secret') view.secret = event.target.value; + else { view.draft[key] = key === 'id' ? event.target.value.toLowerCase().replace(/\s/g, '-') : event.target.value; if (key === 'id') { view.taken = false; event.target.value = view.draft.id; } } + view.generation++; view.result = null; view.error = null; + if (['host', 'port'].includes(key)) { view.scanned = null; view.trusted = false; } + paint(); + }); + view.layer.panel.addEventListener('focusout', event => { + const key = event.target.dataset.credField; if (!key || view.busy) return; + view.touched.add(key); paint(); + }); + view.layer.panel.addEventListener('toggle', event => { + if (event.target.matches('.tc-cred-compare')) { view.compareOpen = event.target.open; return; } + if (!event.target.matches('.tc-wizard-rail-wrap') || !Kit.isPhone()) return; + view.railOpen = event.target.open; event.target.toggleAttribute('data-open', view.railOpen); + }, true); + view.layer.panel.addEventListener('click', async event => { + const button = event.target.closest('[data-cred-editor]'); if (!button || button.disabled || button.tagName === 'INPUT') return; + const action = button.dataset.credEditor; + if (action === 'close') return void view.close('close'); + if (view.busy) return; + if (action === 'copy') return void Kit.copy(S.commands(view.draft, true)[0], button, 'Draft command copied'); + if (action === 'test') return void test(); + if (action === 'replace') { view.replacing = true; paint(); view.layer.panel.querySelector('#cred-secret')?.focus(); return; } + if (action === 'keep-saved') { view.secret = ''; view.replacing = false; view.revealed = false; view.touched.delete('secret'); view.result = null; paint(); view.layer.panel.querySelector('#cred-replace')?.focus(); return; } + if (action === 'reveal') { view.revealed = !view.revealed; paint(); return; } + if (action === 'type') { const id = view.draft.id; view.draft = { ...S.defaults(button.dataset.value), id }; view.secret = ''; view.scanned = null; view.trusted = false; view.result = null; view.touched.clear(); view.revealed = false; paint(); return; } + if (action === 'authType') { view.draft.authType = button.dataset.value; view.draft.authName = button.dataset.value === 'query' ? 'api_key' : 'X-API-Key'; view.draft.authPrefix = ''; view.result = null; view.touched.delete('authName'); paint(); return; } + if (action === 'theirs') { + const current = view.conflict.current, keep = view.original.secretChangedAt === current.secretChangedAt; + view.secret = keep ? view.secret : ''; view.replacing = Boolean(view.secret); view.revealed = false; view.original = current; view.draft = S.draftOf(current); view.revision = current.revision; view.conflict = null; view.scanned = null; view.trusted = false; view.result = null; view.touched.clear(); paint(); return; + } + if (action === 'mine') { view.revision = view.conflict.current.revision; view.conflict = null; return void submit(); } + if (action === 'new') { view.recreateId = view.draft.id; view.create = true; view.original = null; view.conflict = null; view.revision = undefined; view.replacing = true; paint(); if (valid()) void submit(); else view.layer.panel.querySelector('#cred-secret')?.focus(); } + }); + view.layer.panel.addEventListener('change', event => { + if (event.target.dataset.credEditor !== 'trust' || view.busy) return; + view.trusted = event.target.checked; view.result = null; paint(); if (view.trusted) void test(); + }); + view.layer.panel.addEventListener('keydown', event => { if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') { event.preventDefault(); void submit(); } }); + }; + return { open, close, repaint: () => active?.repaint(), beforeNavigate: () => close('route'), isOpen: () => Boolean(active) }; + }; + return { create }; +})(); diff --git a/docker/setup/client/credential-inspector.js b/docker/setup/client/credential-inspector.js new file mode 100644 index 00000000..9c4581f2 --- /dev/null +++ b/docker/setup/client/credential-inspector.js @@ -0,0 +1,58 @@ +const T3CredentialInspector = (() => { + 'use strict'; + const { html, raw, icon } = Kit, S = T3CredentialModel, M = T3Model; + const disabled = value => value ? raw(' disabled') : ''; + const requestPreview = (profile, short = false) => { + const lines = S.request(profile, short).split('\n'); + const mask = text => text.split('••••••••').map((part, index) => html`${index ? html`••••••••` : ''}${part}`); + return html`
${lines.map((line, index) => html`${index ? '\n' : ''}${line.startsWith('GET ') ? html`GET ${mask(line.slice(4))}` : line.startsWith('Host: ') ? html`Host: ${line.slice(6)}` : mask(line)}`)}
`; + }; + const create = ctx => { + let active = null; + const close = reason => { active?.layer.close(reason); return true; }; + const repaint = () => { + if (!active || active.layer.closed) return; + active.layer.panel.classList.toggle('tc-sheet--bottom', Kit.isPhone()); active.layer.render(); + }; + const open = id => { + if (active?.id === id) { repaint(); return; } + close('replaced'); const view = { id, snippetOpen: false }; active = view; + const row = () => ctx.row(id), busy = () => ctx.busy.has(id); + const action = (name, label, options = {}) => html``; + const saved = profile => html`${icon('lock')}Saved ${profile.secretChangedAt ? '· changed ' + S.day(profile.secretChangedAt) : '· from before the upgrade'}${action('replace', 'Replace…', { ghost: true })}`; + const connection = profile => html`

Connection

${profile.type === 'ssh' ? html` +
Host
${profile.host}
Port
${profile.port}
Username
${profile.username}
Password
${saved(profile)}
Host key
${profile.hostKey ? html`${S.keyType(profile.hostKey.type)}${profile.hostKey.fingerprint}trusted ${S.day(profile.hostKey.trustedAt)}${profile.hostKey.carried ? ' · carried over' : ''}` : html`Not trusted yet${action('review', 'Trust…', { ghost: true })}`}
` : html` +
Base URL
${profile.baseUrl}
Auth
${profile.authType === 'header' ? 'Header ' + profile.authName : profile.authType === 'query' ? 'Query parameter ' + profile.authName : 'Bearer token'}
${profile.authType === 'bearer' ? 'Token' : 'Key'}
${saved(profile)}
Test with
GET ${profile.testPath || 'the base URL'}
`}
`; + const bannerActions = profile => { + const state = S.state(profile, { busy: ctx.busy.get(id)?.kind === 'test' }); + return html`
${state.action.startsWith('Review') ? action('review', 'Review…') : state.action.startsWith('Replace') ? action('replace', 'Replace ' + S.secretKind(profile) + '…') : state.action.startsWith('Edit') ? action('edit', 'Edit…') : ''}${!state.action.startsWith('Review') ? action('test', profile.test ? 'Test again' : 'Test now') : ''}
`; + }; + const banner = profile => { + const state = S.state(profile, { busy: ctx.busy.get(id)?.kind === 'test' }); + return html`
${state.icon ? icon(state.icon) : html``}
${state.title}${state.desc ? html`${profile.type === 'api' && profile.test?.ok ? html`GET ${profile.testPath || 'the base URL'} answered HTTP ${profile.test.detail.status} in ${profile.test.ms} ms.` : state.desc}` : ''}
${Kit.isPhone() ? '' : bannerActions(profile)}
${Kit.isPhone() ? bannerActions(profile) : ''}
`; + }; + const snippet = profile => html`
${S.snippet(profile).split('\n').map((line, index) => html`${index ? '\n' : ''}${line.startsWith('t3-ssh ') || line.startsWith('t3-api ') ? html`${line}` : line}`)}
`; + const use = profile => html`

Use it in a skill${action('snippet', 'Copy snippet', { icon: 'copy' })}

${profile.type === 'ssh' ? snippet(profile) : ''}
    ${S.commands(profile).map((command, index) => html`
  • ${command}
  • `)}
${profile.type === 'api' ? html`
Snippet for SKILL.md${snippet(profile)}
` : ''}

${profile.type === 'ssh' ? 'Agents never need the password. Output that repeats it shows [redacted].' : 'Paths are relative to the base URL. JSON bodies go on stdin, up to 1 MiB.'}

`; + const usedIn = profile => html`

Used in${S.usageCount(profile, ctx.usageWarnings()?.length > 0)}

Skills that mention ${id}, from Instructions & skills.${ctx.usageWarnings()?.length ? ' Some skills couldn’t be read.' : ''}

`; + const render = () => { + const profile = row(); + return html`

${id}

${profile ? (profile.type === 'ssh' ? 'SSH' : 'API') + ' · ' + S.auth(profile) + ' · added ' + S.day(profile.createdAt) : 'Credential unavailable'}
${profile ? action('edit', 'Edit', { icon: 'pencil' }) : ''}
${profile ? html`${ctx.errors.get(id) ? html`` : ''}${banner(profile)}${connection(profile)}${profile.type === 'api' ? html`

Every requestStays under the base URL · no redirects

${requestPreview(profile)}
` : ''}${use(profile)}${usedIn(profile)}` : html``}
`; + }; + view.layer = Kit.open({ kind: 'sheet', returnTo: document.activeElement, panel: { class: 'tc-sheet tc-skill-inspector tc-mcp-inspector tc-cred-inspector' + (Kit.isPhone() ? ' tc-sheet--bottom' : ''), role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'cred-inspect-title' }, focus: '[data-cred-inspect="close"]', backdrop: 'ignore', onEscape: () => close('escape'), onClose: reason => { if (active === view) active = null; ctx.inspectorClosed(id, reason); }, render }); + view.layer.panel.addEventListener('toggle', event => { if (event.target.matches('.tc-cred-snippet-detail')) view.snippetOpen = event.target.open; }, true); + view.layer.panel.addEventListener('click', event => { + const button = event.target.closest('[data-cred-inspect]'); if (!button || button.disabled) return; + const action = button.dataset.credInspect, profile = row(); + if (action === 'close') return close('close'); + if (action === 'retry') return void ctx.refresh(); + if (!profile) return; + if (action === 'menu') return ctx.menu(button, profile, true); + if (action === 'snippet') return void Kit.copy(S.snippet(profile), button, 'Skill snippet copied'); + if (action === 'command') return void Kit.copy(S.commands(profile)[Number(button.dataset.index)], button, 'Command copied'); + ctx.action(action, id, button); + }); + }; + return { open, close, repaint, id: () => active?.id || null }; + }; + return { create, requestPreview }; +})(); diff --git a/docker/setup/client/credential-model.js b/docker/setup/client/credential-model.js new file mode 100644 index 00000000..8c05daea --- /dev/null +++ b/docker/setup/client/credential-model.js @@ -0,0 +1,78 @@ +// Pure credential presentation and draft validation. Saved secrets never enter +// this model; request previews and snippets use fixed masks or placeholders. +const T3CredentialModel = (() => { + 'use strict'; + const M = T3Model, C = T3McpCommand; + const fields = ['id', 'type', 'host', 'port', 'username', 'baseUrl', 'authType', 'authName', 'authPrefix', 'testPath']; + const validName = value => typeof value === 'string' && value.length <= 64 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value); + const text = (value, max, optional = false) => typeof value === 'string' && value.isWellFormed() && (optional || value.length > 0) && value.length <= max && !/[\x00-\x1f\x7f]/.test(value); + const defaults = type => ({ id: '', type, host: '', port: 22, username: '', baseUrl: '', authType: 'bearer', authName: 'X-API-Key', authPrefix: '', testPath: '' }); + const draftOf = profile => ({ ...defaults(profile?.type || 'ssh'), ...Object.fromEntries(fields.filter(field => profile?.[field] !== undefined).map(field => [field, profile[field]])) }); + const payload = draft => Object.fromEntries(fields.filter(field => draft[field] !== undefined).map(field => [field, field === 'port' ? Number(draft[field]) : draft[field]])); + const kind = profile => profile.type === 'ssh' ? 'Password' : profile.authType === 'header' ? profile.authName || 'Header key' : profile.authType === 'query' ? '?' + (profile.authName || 'key') : 'Bearer token'; + const secretKind = profile => profile.type === 'ssh' ? 'password' : profile.authType === 'bearer' ? 'token' : 'key'; + const auth = profile => profile.type === 'ssh' ? 'password' : profile.authType === 'header' ? (profile.authName || 'Header') + ' header' : profile.authType === 'query' ? (profile.authName || 'key') + ' query parameter' : 'bearer token'; + const target = profile => profile.type === 'ssh' ? (profile.username || 'user') + '@' + (profile.host || 'host') + (Number(profile.port || 22) !== 22 ? ':' + profile.port : '') : profile.baseUrl; + const usageCount = (profile, partial = false) => { const n = profile.usedIn?.length || 0, unit = profile.usedIn?.some(item => item.kind === 'instructions') ? 'source' : 'skill'; return partial ? n ? 'At least ' + M.plural(n, unit) : 'Unknown' : M.plural(n, unit); }; + const day = value => { const date = new Date(value); return Number.isFinite(date.getTime()) ? date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' }) : 'unknown'; }; + const keyType = type => type === 'ssh-ed25519' ? 'ED25519' : type === 'ssh-rsa' ? 'RSA' : type?.startsWith('ecdsa') ? 'ECDSA' : 'Host key'; + const keyCommand = type => 'ssh-keygen -lf /etc/ssh/ssh_host_' + (type === 'ssh-rsa' ? 'rsa' : type?.startsWith('ecdsa') ? 'ecdsa' : 'ed25519') + '_key.pub'; + const commands = (profile, editing = false) => profile.type === 'ssh' + ? ['t3-ssh ' + (profile.id || 'name') + ' -- ' + (editing ? 'command' : 'uptime'), 't3-ssh ' + (profile.id || 'name') + ' -- bash -s < script.sh'] + : ['t3-api ' + (profile.id || 'name') + ' GET ' + C.quote(profile.testPath || ''), 't3-api ' + (profile.id || 'name') + ' POST --stdin < body.json']; + const snippet = profile => { + if (profile.type === 'ssh') return `Run commands on ${profile.id} with its saved login:\n\nt3-ssh ${profile.id} -- ''\n\nDon’t read or print credential files.`; + let host = profile.baseUrl; try { host = new URL(profile.baseUrl).host; } catch {} + return `Call ${host}’s API with its saved key:\n\nt3-api ${profile.id} GET \nt3-api ${profile.id} POST --stdin < body.json\n\nPaths are relative to ${profile.baseUrl}. Don’t read or print credential files.`; + }; + const request = (profile, short = false) => { + try { + const base = new URL(profile.baseUrl); if (!base.pathname.endsWith('/')) base.pathname += '/'; + const url = new URL(profile.testPath || '.', base); + if (!['http:', 'https:'].includes(base.protocol) || base.username || base.password || url.origin !== base.origin || !url.pathname.startsWith(base.pathname.endsWith('/') ? base.pathname : base.pathname + '/')) return 'Enter a valid base URL and relative test path.'; + if (profile.authType === 'query') url.searchParams.set(profile.authName || 'key', '••••••••'); + const address = (short ? url.pathname + url.search : url.href).replace(/%E2%80%A2/gi, '•'); + const header = profile.authType === 'query' ? '' : profile.authType === 'header' ? (profile.authName || 'X-API-Key') + ': ' + (profile.authPrefix ? profile.authPrefix + ' ' : '') + '••••••••\n' : 'Authorization: Bearer ••••••••\n'; + return 'GET ' + address + '\n' + (short ? 'Host: ' + base.host + '\n' : '') + header + 'accept: application/json'; + } catch { return 'Enter a base URL to preview the request.'; } + }; + const validate = (draft, { editing = false, names = [], secret = '', hasSecret = false } = {}) => { + const errors = {}; + if (!validName(draft.id)) errors.id = 'Use up to 64 lowercase letters, numbers and single hyphens.'; + else if (!editing && names.includes(draft.id)) errors.id = draft.id + ' is taken.'; + if (!['ssh', 'api'].includes(draft.type)) errors.type = 'Choose SSH server or HTTP API.'; + if (draft.type === 'ssh') { + const host = draft.host || ''; let ipv6 = false; + if (host.includes(':')) { try { const [address, zone, extra] = host.split('%'); const addressUrl = 'http://[' + address + ']/'; ipv6 = new URL(addressUrl).hostname.startsWith('[') && extra === undefined && (zone === undefined || /^[a-z0-9_.-]+$/i.test(zone)); } catch {} } + if (!text(host, 253) || !(ipv6 || /^[a-zA-Z0-9][a-zA-Z0-9.-]*$/.test(host))) errors.host = 'Enter a hostname or IP address, without a username or port.'; + if (!Number.isInteger(Number(draft.port)) || Number(draft.port) < 1 || Number(draft.port) > 65535) errors.port = 'Use a port from 1 to 65535.'; + if (!text(draft.username || '', 64) || !/^[a-zA-Z_][a-zA-Z0-9_.-]*\$?$/.test(draft.username)) errors.username = 'Enter a valid SSH username.'; + } else if (draft.type === 'api') { + let base; + try { base = new URL(draft.baseUrl); } catch {} + if (!text(draft.baseUrl || '', 2048) || !base || !['http:', 'https:'].includes(base.protocol) || base.username || base.password || base.search || base.hash) errors.baseUrl = 'Use an HTTP or HTTPS address without credentials, a query or a fragment.'; + if (!['bearer', 'header', 'query'].includes(draft.authType)) errors.authType = 'Choose an authentication method.'; + if (draft.authType !== 'bearer') { + if (!text(draft.authName || '', 128)) errors.authName = 'Enter an authentication header or parameter name.'; + if (draft.authType === 'header') { + if (!/^[!#$%&'*+.^_`|~0-9a-z-]+$/i.test(draft.authName || '') || ['host', 'content-length', 'transfer-encoding', 'connection', 'upgrade', 'expect', 'trailer', 'te', 'accept', 'content-type'].includes(draft.authName?.toLowerCase())) errors.authName = 'Use a valid authentication header, such as X-API-Key.'; + if (typeof draft.authPrefix !== 'string' || draft.authPrefix.length > 128 || /[^\x20-\x7e]/.test(draft.authPrefix)) errors.authPrefix = 'Use up to 128 printable characters for the prefix.'; + } + } + const relative = draft.testPath || ''; + if (!text(relative, 2048, true) || relative.startsWith('/') || relative.includes('\\') || /^[a-z][a-z0-9+.-]*:/i.test(relative)) errors.testPath = 'Use a relative path, such as account.'; + else if (base && !errors.baseUrl) { + if (!base.pathname.endsWith('/')) base.pathname += '/'; + const target = new URL(relative || '.', base); + if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname) || target.hash) errors.testPath = 'The test path must stay under the base URL.'; + } + } + if (secret ? !text(secret, 8192) : !hasSecret) errors.secret = 'Enter a ' + secretKind(draft) + ', up to 8192 characters without line breaks.'; + return errors; + }; + const changes = (previous, current) => fields.filter(field => field !== 'id' && field !== 'type' && String(previous?.[field] ?? '') !== String(current?.[field] ?? '')); + const fieldLabel = field => ({ host: 'Host', port: 'Port', username: 'Username', baseUrl: 'Base URL', authType: 'Authentication', authName: 'Authentication name', authPrefix: 'Prefix', testPath: 'Test path' }[field] || field); + const matches = (profile, query) => !query.trim() || [profile.id, profile.host, profile.username, profile.baseUrl, kind(profile), auth(profile), profile.type].filter(Boolean).join(' ').toLowerCase().includes(query.trim().toLowerCase()); + const needsAttention = (profile, attention) => profile.type === 'ssh' && (!profile.hostKey || profile.test?.code === 'host-key-changed') || profile.test?.ok === false && (profile.test.code !== 'timeout' || attention?.some(row => row.id === profile.id)); + return { fields, validName, defaults, draftOf, payload, kind, secretKind, auth, target, usageCount, day, keyType, keyCommand, commands, snippet, request, validate, changes, fieldLabel, matches, needsAttention, state: M.credentialState }; +})(); diff --git a/docker/setup/client/credentials.js b/docker/setup/client/credentials.js index de53a9f3..5b2fd6c0 100644 --- a/docker/setup/client/credentials.js +++ b/docker/setup/client/credentials.js @@ -1,114 +1,139 @@ -// Saved secrets are write-only. Only the newly typed replacement lives in -// the dialog's input; it is never rendered, cached or copied into instructions. +// On-demand credentials library. Polling never replaces focused inputs or a +// draft, and an item stays pending until its saved truth has been read back. const T3CredentialsUI = (() => { 'use strict'; - const { html, raw, icon } = Kit; + const { html, raw, icon } = Kit, S = T3CredentialModel, M = T3Model; const disabled = value => value ? raw(' disabled') : ''; - const create = ({ api, render }) => { - let data = null, loading = false, error = null, started = false, epoch = 0, editor = null, notice = null; - const busy = new Set(), results = new Map(); - const notify = (message, options) => { notice?.close(); notice = Kit.toast(message, options); }; - const paint = () => { - render(); - const mount = document.getElementById('credential-list'); - if (mount) Kit.patch(mount, body()); + const create = ({ api, getStatus = () => null, render, onChange = async () => {} }) => { + let data = null, error = null, query = '', attentionOnly = false, started = false, loading = false, inFlight = null, epoch = 0, lastDeep = null; + const busy = new Map(), errors = new Map(); + const rows = () => [...(data?.credentials || [])].sort((a, b) => a.id.localeCompare(b.id, 'en')); + const row = id => data?.credentials.find(row => row.id === id); + const usageWarnings = () => data?.usageWarnings || []; + const attention = () => rows().filter(profile => S.needsAttention(profile, getStatus()?.credentials?.attention)); + const testing = () => [...busy.values()].filter(value => value.kind === 'test').length; + const paint = () => { render(); const mount = document.getElementById('credential-list'); if (mount) Kit.patch(mount, body()); inspector.repaint(); }; + const load = (force = false) => { + if (inFlight && !force) return inFlight; + const version = ++epoch; started = true; loading = true; error = null; paint(); + const work = api('/credentials').then(response => { + if (version !== epoch) return false; + if (response.ok && Array.isArray(response.data?.credentials)) { data = response.data; return true; } + error = response.error || 'Saved credentials could not be read. Restore the credential file before making changes.'; data = null; return false; + }).finally(() => { if (version === epoch) { loading = false; inFlight = null; paint(); } }); + inFlight = work; return work; }; - const load = async () => { - const version = ++epoch; - started = true; loading = true; error = null; paint(); - const response = await api('/credentials'); - if (version !== epoch) return; - if (response.ok && Array.isArray(response.data?.credentials)) data = { ...response.data, profiles: response.data.credentials.map(row => ({ ...row, label: row.id })) }; - else error = response.error || 'Could not load saved connections.'; - loading = false; paint(); + const request = async (id, kind, route, input, { refresh = true } = {}) => { + if (busy.has(id)) return null; + const focused = document.activeElement?.getAttribute('data-key'); + busy.set(id, { kind }); errors.delete(id); paint(); + let response; + try { + response = await api(route, { body: input }); + if (!response.ok) errors.set(id, response.error || 'This action did not finish. Try again.'); + if (refresh) await Promise.all([load(true), onChange()]); + return response; + } finally { + busy.delete(id); paint(); + if (focused && document.activeElement === document.body) document.querySelector('[data-key="' + CSS.escape(focused) + '"]')?.focus({ preventScroll: true }); + } + }; + const inspect = id => { if (row(id)) inspector.open(id); }; + const edit = async (id, replace = false) => { + if (id && busy.has(id) || error) return; + const profile = id ? row(id) : null; if (id && !profile) return; + inspector.close('edit'); await editor.open(profile, { replace }); }; - const command = profile => profile.type === 'ssh' ? 't3-ssh ' + profile.id + ' -- uptime' : 't3-api ' + profile.id + ' GET ' + T3McpCommand.quote(profile.testPath || ''); - const body = () => html` -
${data ? T3Model.plural(data.profiles.length, 'saved connection') : 'Saved connections'}
- ${error ? html`` : ''} - ${!data ? html`
${loading ? 'Loading connections…' : 'Connections unavailable'}
` : data.profiles.length ? html`
${data.profiles.map(profile => html` -
- -
${profile.label}${profile.type === 'ssh' ? profile.username + '@' + profile.host + ':' + profile.port : profile.baseUrl}
${command(profile)}
${profile.type === 'ssh' ? 'Password saved' : profile.authType === 'header' ? 'Header key saved' : profile.authType === 'query' ? 'Query key saved' : 'Bearer token saved'} · ••••••••${results.has(profile.id) ? html`${results.get(profile.id).message}` : ''}
-
-
`)}
` : html`
Save a connection once

Keep SSH passwords and API keys here. Your skills use the connection ID, so credentials stay out of instructions and chat.

`} -

${icon('lock-keyhole', 'tc-icon--sm')}Saved on this server. Values are hidden from the page and filtered from helper output. Any agent with shell access can use these connections.

`; - - const openEditor = profile => { - if (editor || !data || error || loading) return; - notice?.close(); notice = null; - const view = { original: profile, revision: profile?.revision, draft: profile ? { ...profile } : { id: '', label: '', type: 'ssh', host: '', username: '', port: 22, baseUrl: '', authType: 'bearer', authName: 'X-API-Key', authPrefix: '', testPath: '' }, busy: false, error: null }; - editor = view; - const field = (key, label, options = {}) => html`
${options.hint ? html`

${options.hint}

` : ''}
`; - const markup = () => html`
-

${profile ? 'Edit connection' : 'Add connection'}

${profile ? 'Leave the secret blank to keep its saved value.' : 'Save the login here, then use its connection ID in your skills.'}

-
- ${field('label', 'Name', { max: 120 })} - ${field('id', 'Connection ID', { locked: Boolean(profile), max: 64, hint: 'Lowercase letters, numbers and hyphens. Used in helper commands.' })} -
- ${view.draft.type === 'ssh' ? html`${field('host', 'Host', { max: 253 })}
${field('username', 'Username', { max: 64 })}${field('port', 'Port', { type: 'number' })}
` : html` - ${field('baseUrl', 'API base URL', { max: 2048, hint: 'Include the API version or base path, for example https://api.example.com/v1/.' })} -
- ${view.draft.authType === 'header' ? html`${field('authName', 'Header name', { max: 128, hint: 'For example X-API-Key, api-key or Authorization.' })}${field('authPrefix', 'Value prefix (optional)', { max: 128, required: false, hint: 'For example Token. Leave blank to send the key as the complete header value.' })}` : view.draft.authType === 'query' ? field('authName', 'Query parameter name', { max: 128, hint: 'For APIs that require a key in the URL. Prefer a header when supported.' }) : ''} - ${field('testPath', 'Test path (optional)', { max: 2048, required: false, hint: 'A relative GET endpoint that requires authentication; blank uses the base URL.' })}`} -

${profile ? 'A value is saved. Enter a replacement only if you want to change it.' : 'This value will not appear in the saved connection details.'}

-
${view.error ? html`` : ''} -
`; - const close = () => { if (!view.busy) view.layer.close(); }; - view.layer = Kit.open({ kind: 'center', backdrop: 'ignore', focus: '#credential-label', - panel: { tag: 'form', class: 'tc-dialog tc-credential-editor', role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'credential-title', autocomplete: 'off' }, - render: markup, onEscape: close, onClose: () => { const input = view.layer.panel.querySelector('#credential-secret'); if (input) input.value = ''; if (editor === view) editor = null; }, - }); - view.layer.panel.addEventListener('input', event => { - const key = event.target.dataset.credentialField; - if (key && !view.busy) view.draft[key] = event.target.value; - }); - view.layer.panel.addEventListener('change', event => { - if (event.target.dataset.credentialField === 'type' && !view.busy) { view.draft.type = event.target.value; view.layer.render(); } - if (event.target.dataset.credentialField === 'authType' && !view.busy) { view.draft.authType = event.target.value; view.draft.authName = event.target.value === 'query' ? 'api_key' : 'X-API-Key'; view.draft.authPrefix = ''; view.layer.render(); } - }); - view.layer.panel.addEventListener('click', event => { if (event.target.closest('[data-credential-cancel]')) close(); }); - view.layer.panel.addEventListener('submit', async event => { - event.preventDefault(); - if (view.busy || editor !== view) return; - const secretInput = view.layer.panel.querySelector('#credential-secret'); - const payload = { ...view.draft, port: Number(view.draft.port), secret: secretInput.value || undefined }; - view.busy = true; view.error = null; view.layer.render(); - const response = await api(profile ? '/credentials/save' : '/credentials/create', { body: { credential: payload, revision: view.revision } }); - delete payload.secret; - if (response.ok) { - secretInput.value = ''; results.delete(view.draft.id); - if (editor === view) { view.busy = false; view.layer.close('saved'); } - notify('Connection saved'); await load(); - } else if (editor === view) { - view.busy = false; view.error = response.error; view.layer.render(); - view.layer.panel.querySelector('#credential-error')?.focus(); - } - }); + const ctx = { api, busy, errors, rows, row, usageWarnings, loadError: () => error, refresh: () => load(true), request, + saved: async credential => { + if (data) data.credentials = [...data.credentials.filter(row => row.id !== credential.id), { ...credential, usedIn: row(credential.id)?.usedIn || [] }]; + errors.delete(credential.id); const [loaded] = await Promise.all([load(true), onChange()]); return loaded; + }, + deleted: id => { + if (inspector.id() === id) inspector.close('removed'); + if (location.hash === '#credentials/' + id) history.replaceState(null, '', '#credentials'); + paint(); + requestAnimationFrame(() => { + const next = document.querySelector('#credential-list [data-cred-action="inspect"], #credential-list [data-cred-action="add"], #credential-list [data-cred-action="retry"]'); + next?.focus({ preventScroll: true }); + }); + }, + inspectorClosed: (id, reason) => { if (!['route', 'replaced'].includes(reason) && location.hash === '#credentials/' + id) { history.replaceState(null, '', '#credentials'); lastDeep = null; } }, + action: (action, id, button) => { void actionFor(action, id, button); }, menu: (button, profile, details) => menu(button, profile, details), review: id => dialogs.review(id), }; - document.addEventListener('click', async event => { - const button = event.target.closest('[data-credential-action]'); - if (!button || button.disabled) return; - const action = button.dataset.credentialAction, profile = data?.profiles.find(row => row.id === button.dataset.id); - if (action === 'reload') { void load(); return; } - if (action === 'add') { openEditor(); return; } - if (action === 'copy' && profile) { void Kit.copy(command(profile), button, 'Skill command copied'); return; } - if (!profile || busy.has(profile.id) || error) return; - if (action === 'edit') { openEditor(profile); return; } - const revision = profile.revision; - if (action === 'remove') { - const yes = await Kit.confirm({ title: 'Delete ' + profile.label + '?', body: 'Removes the saved login. Skills using ' + profile.id + ' will need another connection.', confirm: 'Delete connection', tone: 'danger' }); - if (!yes || busy.has(profile.id)) return; + const inspector = T3CredentialInspector.create(ctx), editor = T3CredentialEditor.create(ctx), dialogs = T3CredentialDialogs.create(ctx); + const actionFor = async (action, id, button) => { + if (action === 'add') { if (!data && !await load()) return; return edit(); } + if (action === 'retry') return load(true).then(loaded => { if (loaded) return activate(); }); + if (action === 'clear') { query = ''; attentionOnly = false; paint(); const input = document.getElementById('credential-search'); if (input) input.value = ''; return; } + if (action === 'attention') { attentionOnly = !attentionOnly; paint(); return; } + const profile = row(id); if (!profile) return; + if (action === 'inspect') return inspect(id); + if (action === 'menu') return menu(button, profile); + if (action === 'copy-name') return Kit.copy(profile.id, button, 'Credential name copied'); + if (action === 'copy-command') return Kit.copy(S.commands(profile)[0], button, 'Command copied'); + if (busy.has(id) || error) return; + if (action === 'edit' || action === 'replace') return edit(id, action === 'replace'); + if (action === 'review') { if (profile.test?.code === 'host-key-changed' || !profile.hostKey && inspector.id() === id) return dialogs.review(id); return inspect(id); } + if (action === 'delete') return dialogs.remove(id); + if (action === 'forget') return dialogs.forget(id); + if (action === 'test') { + if (testing() >= 3) return Kit.announce('Three tests are already running. Wait for one to finish.'); + const response = await request(id, 'test', '/credentials/test', { id }); + if (response?.ok && response.data.result) Kit.announce(response.data.result.ok ? id + ' connected.' : id + ': ' + M.credentialProblem(response.data.result.code)); } - busy.add(profile.id); results.delete(profile.id); paint(); - const response = await api('/credentials/' + action, { body: { id: profile.id, revision } }); - busy.delete(profile.id); - if (action === 'test') results.set(profile.id, { ok: response.ok && response.data?.result?.ok, message: response.ok ? response.data?.result?.code === 'ok' ? 'Connection succeeded' : 'Connection needs attention: ' + response.data?.result?.code : response.error }); - else if (response.ok) notify('Connection deleted'); - else notify('Could not delete connection', { tone: 'danger', detail: response.error }); - await load(); - }); - return { content: () => html`
${body()}
`, activate: (force = false) => { if (!loading && (force || !started)) void load(); } }; + }; + const menu = (button, profile, details = false) => Kit.menu(button, { label: 'More for ' + profile.id, head: profile.id, items: [ + { label: 'Test', icon: 'refresh-cw', disabled: busy.has(profile.id) || testing() >= 3, run: () => actionFor('test', profile.id, button) }, + { label: 'Edit…', icon: 'pencil', disabled: busy.has(profile.id), run: () => edit(profile.id) }, + { label: 'Copy name', icon: 'copy', run: () => actionFor('copy-name', profile.id, button) }, + { label: 'Copy command', icon: 'terminal', run: () => actionFor('copy-command', profile.id, button) }, + ...(details && profile.type === 'ssh' && profile.hostKey ? [{ label: 'Forget host key…', icon: 'shield-alert', disabled: busy.has(profile.id), run: () => dialogs.forget(profile.id) }] : []), + { sep: true }, { label: 'Delete…', icon: 'trash-2', danger: true, disabled: busy.has(profile.id), run: () => dialogs.remove(profile.id) }, + ] }); + const footer = () => html`
${icon('lock', 'tc-icon--sm')}${Kit.isPhone() ? 'Saved in plain text on this server. Chats and skills only need the name.' : 'Saved in plain text on this server’s volume. Anything running here can read them; chats and skills only need the name.'}
`; + const nameBadge = profile => html`${profile.type === 'ssh' ? 'SSH' : 'API'}`; + const rowState = profile => S.state(profile, { busy: busy.get(profile.id)?.kind === 'test' }); + const dot = tone => html``; + const primary = profile => { + const state = rowState(profile), action = state.action.startsWith('Review') ? 'review' : state.action.startsWith('Replace') ? 'replace' : state.action.startsWith('Edit') ? 'edit' : 'test'; + return html``; + }; + const item = profile => { + const state = rowState(profile), pending = busy.has(profile.id); + if (Kit.isPhone()) return html``; + return html`
${nameBadge(profile)}
${icon(profile.type === 'ssh' ? 'server' : 'globe')}${S.target(profile)}
${icon('key-round')}${S.kind(profile)}${!usageWarnings().length || profile.usedIn?.length ? html`${icon('book-open')}${profile.usedIn?.length ? html`Used in ${profile.usedIn.map(item => item.name).join(', ')}` : 'Not in a skill yet'}` : ''}
${errors.get(profile.id) ? html`${errors.get(profile.id)}` : ''}
${pending ? html`` : dot(state.tone)}${busy.get(profile.id)?.kind === 'scan' ? 'Reading host key…' : busy.get(profile.id)?.kind === 'trust' ? 'Trusting host key…' : state.label}${state.sub ? html`${state.sub}` : ''}
${primary(profile)}
`; + }; + const toolbar = () => html`
${attention().length || attentionOnly ? html`` : ''}
`; + const empty = () => html`
Keep secrets out of chats and skills

Save an SSH or API login here once. Agents use it by name, and never need the secret itself.

1Save a login once

An SSH password or an API key, with where it goes. It stays on this server.

2Use its name in a skill

Skills and chats only ever carry the name.

t3-ssh build-server -- uptime
3The helper signs in

t3-ssh and t3-api add the secret, and hide it if the output repeats it.

${footer()}
`; + const body = () => { + if (error) return html``; + if (!data) return html`
${[1, 2, 3].map(index => html``)}
`; + if (!data.credentials.length) return empty(); + const filtered = rows().filter(profile => S.matches(profile, query) && (!attentionOnly || attention().some(row => row.id === profile.id))); + return html`${toolbar()}${usageWarnings().length ? html`

${icon('info', 'tc-icon--sm')}Some skills couldn’t be read. Usage may be incomplete.

` : ''}
${filtered.length ? filtered.map(item) : html`
${attentionOnly ? 'No matching credentials need attention' : 'No credentials match this search'}
`}
${footer()}
`; + }; + document.addEventListener('click', event => { const button = event.target.closest('[data-cred-action]'); if (!button || button.disabled) return; void actionFor(button.dataset.credAction, button.dataset.id, button); }); + document.addEventListener('input', event => { if (event.target.id !== 'credential-search') return; query = event.target.value; paint(); }); + window.addEventListener('focus', () => { if (started && location.hash.replace(/^#\/?/, '').split('/')[0] === 'credentials' && !editor.isOpen()) void load(); }); + const resize = new ResizeObserver(() => { if (started) { paint(); editor.repaint(); } }); + resize.observe(document.documentElement); + const activate = async (force = false) => { + const id = location.hash.replace(/^#\/?/, '').split('/')[1]; + const loaded = force || !started ? await load() : Boolean(data); if (!loaded) return; paint(); + if (S.validName(id) && !editor.isOpen() && lastDeep !== id) { + lastDeep = id; + if (row(id)) { inspect(id); if (row(id).test?.code === 'host-key-changed') void dialogs.review(id); } + else Kit.toast('Credential not found', { detail: 'It may have been deleted in another window.' }); + } else if (!id) lastDeep = null; + }; + return { + content: () => html`
${body()}
`, + activate, + paletteItems: () => rows().filter(profile => !getStatus()?.credentials?.attention?.some(item => item.id === profile.id)).map(profile => ({ id: 'credential:' + profile.id, group: 'Credentials', label: profile.id, icon: 'key-round', cmd: { cmd: 'goto', route: 'credentials/' + profile.id }, keywords: 'credential ' + profile.type + ' ' + S.target(profile) + ' ' + S.kind(profile), meta: { text: rowState(profile).label } })), + focusSearch: () => { document.getElementById('credential-search')?.focus(); }, + beforeNavigate: async () => { if (!dialogs.beforeNavigate()) { Kit.announce('Wait for the host-key check to finish.'); return false; } return editor.beforeNavigate(); }, + }; }; return { create }; })(); diff --git a/docker/setup/client/model.js b/docker/setup/client/model.js index d2d28142..5b4e8425 100644 --- a/docker/setup/client/model.js +++ b/docker/setup/client/model.js @@ -1355,7 +1355,40 @@ const T3Model = (() => { }; // Credential copy is shared by list, sheets and Overview attention. - const CREDENTIAL_RESULTS = {"ssh":{"ok":{"tone":"ok","row":["Connected","{when}"],"sheet":{"title":"Connected {when}","desc":"Signed in as {user}. The host key matched."},"action":"Test"},"auth-rejected":{"tone":"danger","row":["Password rejected","{when}"],"sheet":{"title":"Password rejected","desc":"{host} didn’t accept the saved password for {user}. Replace it if it changed."},"action":"Replace…"},"unreachable":{"tone":"danger","row":["Unreachable","{when}"],"sheet":{"title":"Couldn’t reach {host}","desc":"Nothing answered on port {port}. Check the address, and that the server is on and allows SSH from here."},"action":"Test"},"timeout":{"tone":"danger","row":["Timed out","{when}"],"sheet":{"title":"Timed out","desc":"{host} didn’t finish signing in within 15 seconds."},"action":"Test"},"host-key-untrusted":{"tone":"warn","row":["Host key not trusted yet","Agents can’t connect yet"],"sheet":{"title":"Host key not trusted yet","desc":"Compare {host}’s key with the server’s own, then trust it. Nothing signs in until you do."},"action":"Review…"},"host-key-changed":{"tone":"warn","row":["Host key changed","Blocked until you review it"],"sheet":{"title":"Host key changed","desc":"{host} presents a different key than the one you trusted. Agents can’t connect until you review it."},"action":"Review…"},"scan-failed":{"tone":"danger","row":["Couldn’t read the host key","{when}"],"sheet":{"title":"Couldn’t read {host}’s host key","desc":"It answered on port {port} but didn’t offer an ed25519, ECDSA or RSA key."},"action":"Test"},"failed":{"tone":"danger","row":["Failed","{when}"],"sheet":{"title":"Couldn’t sign in","desc":"SSH said: {line}"},"action":"Test"}},"api":{"ok":{"tone":"ok","row":["Connected · HTTP {status}","{when}"],"sheet":{"title":"Connected {when}","desc":"GET {path} answered HTTP {status} in {ms} ms."},"action":"Test"},"rejected":{"tone":"danger","row":["Rejected · HTTP {status}","{when}"],"sheet":{"title":"Rejected · HTTP {status}","desc":"Tested {when}. The service didn’t accept the saved {secretKind}. Replace it if it was revoked or expired."},"action":"Replace…"},"not-found":{"tone":"danger","row":["Test path not found · HTTP 404","{when}"],"sheet":{"title":"Test path not found","desc":"GET {path} answered HTTP 404. Check the test path and the base URL’s version."},"action":"Edit…"},"http-error":{"tone":"danger","row":["HTTP {status}","{when}"],"sheet":{"title":"The service answered HTTP {status}","desc":"GET {path} didn’t succeed. A test path must be an endpoint that accepts GET."},"action":"Test"},"redirect":{"tone":"danger","row":["Redirected","{when}"],"sheet":{"title":"The service redirected the request","desc":"Requests never follow redirects, so the key isn’t sent elsewhere. Use the address it redirects to as the base URL."},"action":"Edit…"},"certificate":{"tone":"danger","row":["Certificate not trusted","{when}"],"sheet":{"title":"Certificate not trusted","desc":"{host}’s HTTPS certificate didn’t verify, so the key wasn’t sent."},"action":"Test"},"unreachable":{"tone":"danger","row":["Unreachable","{when}"],"sheet":{"title":"Couldn’t reach {host}","desc":"The address didn’t resolve or didn’t answer. Check it, and this server’s network."},"action":"Test"},"timeout":{"tone":"danger","row":["Timed out","{when}"],"sheet":{"title":"Timed out","desc":"{host} didn’t answer within 15 seconds."},"action":"Test"}},"untested":{"tone":"muted","attention":false,"row":["Not tested yet",""],"sheet":{"title":"Not tested yet","desc":"Test it once to know agents can use it."},"action":"Test"},"testing":{"tone":"muted","row":["Testing…",""],"sheet":{"title":"Testing…","desc":""}}}; + const CREDENTIAL_RESULTS = { + ssh: { + "ok": {"tone": "ok", "row": ["Connected", "{when}"], "sheet": {"title": "Connected {when}", "desc": "Signed in as {user}. The host key matched."}, "action": "Test"}, + "auth-rejected": {"tone": "danger", "row": ["Password rejected", "{when}"], "sheet": {"title": "Password rejected", "desc": "{host} didn’t accept the saved password for {user}. Replace it if it changed."}, "action": "Replace…"}, + "unreachable": {"tone": "danger", "row": ["Unreachable", "{when}"], "sheet": {"title": "Couldn’t reach {host}", "desc": "Nothing answered on port {port}. Check the address, and that the server is on and allows SSH from here."}, "action": "Test"}, + "timeout": {"tone": "danger", "row": ["Timed out", "{when}"], "sheet": {"title": "Timed out", "desc": "{host} didn’t finish signing in within 15 seconds."}, "action": "Test"}, + "host-key-untrusted": {"tone": "warn", "row": ["Host key not trusted yet", "Agents can’t connect yet"], "sheet": {"title": "Host key not trusted yet", "desc": "Compare {host}’s key with the server’s own, then trust it. Nothing signs in until you do."}, "action": "Review…"}, + "host-key-changed": {"tone": "warn", "row": ["Host key changed", "Blocked until you review it"], "sheet": {"title": "Host key changed", "desc": "{host} presents a different key than the one you trusted. Agents can’t connect until you review it."}, "action": "Review…"}, + "scan-failed": {"tone": "danger", "row": ["Couldn’t read the host key", "{when}"], "sheet": {"title": "Couldn’t read {host}’s host key", "desc": "It answered on port {port} but didn’t offer an ed25519, ECDSA or RSA key."}, "action": "Test"}, + "failed": {"tone": "danger", "row": ["Failed", "{when}"], "sheet": {"title": "Couldn’t sign in", "desc": "SSH said: {line}"}, "action": "Test"}, + }, + api: { + "ok": {"tone": "ok", "row": ["Connected · HTTP {status}", "{when}"], "sheet": {"title": "Connected {when}", "desc": "GET {path} answered HTTP {status} in {ms} ms."}, "action": "Test"}, + "rejected": {"tone": "danger", "row": ["Rejected · HTTP {status}", "{when}"], "sheet": {"title": "Rejected · HTTP {status}", "desc": "Tested {when}. The service didn’t accept the saved {secretKind}. Replace it if it was revoked or expired."}, "action": "Replace…"}, + "not-found": {"tone": "danger", "row": ["Test path not found · HTTP 404", "{when}"], "sheet": {"title": "Test path not found", "desc": "GET {path} answered HTTP 404. Check the test path and the base URL’s version."}, "action": "Edit…"}, + "http-error": {"tone": "danger", "row": ["HTTP {status}", "{when}"], "sheet": {"title": "The service answered HTTP {status}", "desc": "GET {path} didn’t succeed. A test path must be an endpoint that accepts GET."}, "action": "Test"}, + "redirect": {"tone": "danger", "row": ["Redirected", "{when}"], "sheet": {"title": "The service redirected the request", "desc": "Requests never follow redirects, so the key isn’t sent elsewhere. Use the address it redirects to as the base URL."}, "action": "Edit…"}, + "certificate": {"tone": "danger", "row": ["Certificate not trusted", "{when}"], "sheet": {"title": "Certificate not trusted", "desc": "{host}’s HTTPS certificate didn’t verify, so the key wasn’t sent."}, "action": "Test"}, + "unreachable": {"tone": "danger", "row": ["Unreachable", "{when}"], "sheet": {"title": "Couldn’t reach {host}", "desc": "The address didn’t resolve or didn’t answer. Check it, and this server’s network."}, "action": "Test"}, + "timeout": {"tone": "danger", "row": ["Timed out", "{when}"], "sheet": {"title": "Timed out", "desc": "{host} didn’t answer within 15 seconds."}, "action": "Test"}, + }, + untested: { + "tone": "muted", + "attention": false, + "row": ["Not tested yet", ""], + "sheet": {"title": "Not tested yet", "desc": "Test it once to know agents can use it."}, + "action": "Test", + }, + testing: { + "tone": "muted", + "row": ["Testing…", ""], + "sheet": {"title": "Testing…", "desc": ""}, + }, + }; const credentialState = (profile, { busy = false, now = Date.now() } = {}) => { const result = profile.test, code = busy ? 'testing' : profile.type === 'ssh' && !profile.hostKey ? 'host-key-untrusted' : result?.code || 'untested'; const source = CREDENTIAL_RESULTS[code] || CREDENTIAL_RESULTS[profile.type]?.[code] || CREDENTIAL_RESULTS.untested; @@ -1366,7 +1399,7 @@ const T3Model = (() => { path: profile.testPath || 'the base URL', secretKind: profile.authType === 'bearer' ? 'token' : profile.type === 'ssh' ? 'password' : 'key' }; const fill = text => String(text || '').replace(/\{(\w+)\}/g, (_, name) => values[name] ?? ''); return { code, tone: source.tone, label: fill(source.row[0]), sub: fill(source.row[1]), title: fill(source.sheet.title), desc: fill(source.sheet.desc), - action: source.action || 'Test', at: result?.at || null, icon: busy ? null : source.tone === 'ok' ? 'circle-check' : source.tone === 'warn' ? 'triangle-alert' : source.tone === 'danger' ? 'circle-x' : 'circle-help' }; + action: source.action || 'Test', at: result?.at || null, icon: busy ? null : source.tone === 'ok' ? 'circle-check' : source.tone === 'warn' ? 'triangle-alert' : source.tone === 'danger' ? 'circle-x' : 'info' }; }; const credentialProblem = code => { const text = CREDENTIAL_RESULTS.ssh[code]?.row[0] || CREDENTIAL_RESULTS.api[code]?.row[0] || 'Connection needs attention'; @@ -1668,6 +1701,10 @@ const T3Model = (() => { add(item.id === 'runtime' ? 'Updates' : 'Server', fixes[item.id], item.icon, item.action.cmd === 'goto' ? { cmd: 'goto', route: item.action.route } : { cmd: item.action.cmd, id: item.action.id }, { attention: true }); } + for (const item of s.credentials?.attention || []) { + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(item.id || '') || item.id.length > 64) continue; + add('Credentials', item.id, 'key-round', { cmd: 'goto', route: 'credentials/' + item.id }, { attention: true, meta: { text: credentialProblem(item.code), dot: String(item.code || '').startsWith('host-key') ? 'warn' : 'danger' }, keywords: 'credential ssh api key password token secret ' + item.id }); + } add('MCP servers', 'Add MCP server…', 'plug', { cmd: 'mcp.add' }); add('MCP servers', 'Rescan MCP servers', 'refresh-cw', { cmd: 'mcp.refresh' }); for (const server of s.context?.mcp?.shared?.servers || []) add('MCP servers', server.name, 'plug', { cmd: 'mcp.view', id: server.name }); diff --git a/docker/setup/client/routes.js b/docker/setup/client/routes.js index 450f73ce..c8c35eda 100644 --- a/docker/setup/client/routes.js +++ b/docker/setup/client/routes.js @@ -31,7 +31,7 @@ const T3Routes = (() => { summary: 'Servers your agents can start or connect to.', doc: 'mcp-servers.md', palette: { meta: 'Setup · shared definitions and provider configuration', terms: ['mcp tools servers'] } }, { route: 'credentials', title: 'Credentials', icon: 'key-round', key: 'c', group: 'agents', - summary: 'Saved logins your skills can use, without putting passwords or keys in chat.', doc: 'credentials.md', palette: { meta: 'Setup · SSH and API logins agents use by name', terms: ['ssh', 'api key', 'token', 'password', 'secret', 'server credentials'] } }, + summary: 'SSH and API logins your agents use by name. Secrets stay out of chats and skills.', doc: 'credentials.md', palette: { meta: 'Setup · SSH and API logins agents use by name', terms: ['ssh', 'api key', 'token', 'password', 'secret', 'server credentials'] } }, { route: 'files', title: 'Files', icon: 'folder', key: 'f', group: 'tools', summary: 'Your projects, your home folder and what fills the disk.', doc: 'files.md', palette: { meta: 'Setup · projects, the home folder and disk use', terms: ['upload download', 'workspace'] } }, @@ -97,7 +97,7 @@ const T3Routes = (() => { /** The page an address names, through its aliases; null when it names none. */ const resolve = (name) => (BY_ROUTE.has(name) ? name : ALIASES[name] || null); /** The tab that holds a page on a phone. */ - const destination = name => resolve(name) || DESTINATIONS.find(item => item.hash === name)?.hash || null; + const destination = name => resolve(name) || DESTINATIONS.find(item => item.hash === name)?.hash || (typeof name === 'string' && /^credentials\/[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name) && name.slice(12).length <= 64 ? name : null); const tabOf = (route) => (TABS.some((tab) => tab.route === route) ? route : 'more'); /** Pages in their sidebar groups, each group with its label. */ const grouped = () => GROUPS.map((group) => ({ ...group, pages: PAGES.filter((p) => p.group === group.id) })); diff --git a/docker/setup/console.css b/docker/setup/console.css index e12d024b..a2a69033 100644 --- a/docker/setup/console.css +++ b/docker/setup/console.css @@ -3183,37 +3183,6 @@ body[data-console-route="files"]:has(.tc-layer) .tc-toaster { visibility: hidden .tc-files-zip .tc-opt small { overflow-wrap: anywhere; } .tc-files-archive-contents span:not(.tc-small) { max-width: 100%; min-width: 0; } .tc-files-archive-contents code { min-width: 0; overflow-wrap: anywhere; } -/* Server logins use the console's existing forms and controls. Long addresses - wrap independently of the actions, including in the embedded phone view. */ -.tc-credential-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; } -.tc-credential-row { display: flex; align-items: flex-start; gap: 12px; padding: 20px; } -.tc-credential-row + .tc-credential-row { border-top: 1px solid var(--border); } -.tc-credential-main { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: 6px; } -.tc-credential-main strong { font-size: 14px; overflow-wrap: anywhere; } -.tc-credential-address, .tc-credential-command { overflow-wrap: anywhere; } -.tc-credential-command { font-size: 12px; color: var(--fg-muted); } -.tc-credential-usage { display: flex; align-items: center; gap: 8px; } -.tc-credential-usage .tc-copyfield-value { min-width: 0; white-space: normal; overflow-wrap: anywhere; } -.tc-credential-usage .tc-btn { flex: none; } -.tc-credential-actions { display: flex; gap: 8px; flex-wrap: wrap; } -.tc-credential-note { display: flex; align-items: flex-start; gap: 8px; margin-top: 16px; } -.tc-credential-note svg { flex: 0 0 auto; margin-top: 2px; } -.tc-layer--center > .tc-credential-editor { display: flex; flex-direction: column; width: min(520px, calc(100vw - 24px)); overflow: hidden; } -.tc-credential-editor > .tc-dialog-body { min-height: 0; overflow-y: auto; } -.tc-credential-editor > .tc-dialog-foot { flex: none; } -.tc-credential-editor .tc-form { margin-top: 12px; } -.tc-credential-fields { display: grid; grid-template-columns: minmax(0, 1fr) 110px; gap: 12px; } -@media (max-width: 600px) { - .tc-credential-row { padding: 16px; flex-wrap: wrap; } - .tc-credential-main { flex-basis: calc(100% - 56px); } - .tc-credential-actions { margin-left: 44px; } - .tc-credential-toolbar > .tc-small { flex-basis: 100%; } -} -.tc-root[data-density="touch"] :is(.tc-credential-actions, .tc-credential-toolbar, .tc-credential-usage, .tc-credential-editor .tc-dialog-foot) .tc-btn { min-height: var(--touch); min-width: var(--touch); } -@media (max-width: 1023.98px) { - .tc-layer--center > .tc-credential-editor { width: 100%; max-width: none; } -} - /* The Settings breadcrumb stays with the page while its content scrolls. */ .tc-console-topbar { flex: none; height: var(--topbar); min-height: var(--topbar); border-bottom: 1px solid var(--border); padding-inline: var(--space-4); background: var(--bg); } .tc-console-topbar .tc-crumbs { gap: var(--space-3); } @@ -3388,3 +3357,259 @@ body[data-console-route="files"]:has(.tc-layer) .tc-toaster { visibility: hidden @container files-card (max-width: 720px) { #files-browser .tc-files-selection-actions :is([data-cmd="files.compress"], [data-cmd="files.move"], [data-cmd="files.details"]) { display: none; } } +/* Credentials uses the shared list, sheet, wizard, dialog and menu components. + Layout responds to the frame's data-compact density, including Settings. */ + +/* ------------------------------------------------------------- the list --- */ +.tc-cred-list > .tc-row { grid-template-columns: auto minmax(0, 1fr) 14.5rem 8rem; padding-block: 0.875rem; align-items: center; } +.tc-cred-list > .tc-row > .tc-tile { align-self: start; margin-top: 2px; } +.tc-cred-name { display: flex; align-items: center; gap: 0.5rem; min-width: 0; } +.tc-cred-name > button { appearance: none; border: 0; padding: 0; background: none; font: inherit; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; color: var(--fg); + cursor: pointer; text-decoration: none; } +.tc-cred-name > button:hover { text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 3px; } +.tc-cred-name .tc-badge, .tc-cred-prow .tc-prow-name .tc-badge { height: 1.125rem; font-size: 0.6875rem; font-weight: 500; color: var(--fg-muted); background: color-mix(in srgb, var(--fg) 5%, transparent); } +.tc-cred-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; } +.tc-cred-main > .tc-keys { margin-top: 1px; } +.tc-cred-state { display: flex; flex-direction: column; gap: 1px; min-width: 0; font-size: 0.75rem; line-height: 1.125rem; } +.tc-cred-state-line { display: flex; align-items: center; gap: 0.375rem; color: var(--fg); font-weight: 500; min-width: 0; } +.tc-cred-state-line > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tc-cred-state-line[data-tone="warn"] { color: var(--warn-text); } +.tc-cred-state-line[data-tone="danger"] { color: var(--danger-text); } +.tc-cred-state-line[data-tone="muted"] { color: var(--fg-muted); font-weight: 400; } +.tc-cred-state-sub { color: var(--fg-muted); padding-left: calc(0.375rem + 0.375rem); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tc-cred-used { display: inline-flex; align-items: center; gap: 0.3125rem; font-size: 0.75rem; line-height: 1.125rem; color: var(--fg-muted); min-width: 0; } +.tc-cred-used > .tc-icon { width: 0.75rem; height: 0.75rem; flex: none; } +.tc-cred-used b { font-weight: 500; color: var(--fg); } +.tc-cred-used > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tc-cred-meta { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; min-width: 0; } +.tc-cred-meta > .tc-keys { margin-top: 0; } +.tc-cred-list .tc-row-actions .tc-btn--sm { min-width: 3.75rem; justify-content: center; } +.tc-cred-list .tc-row-actions .tc-btn--icon { min-width: 0; } +.tc-cred-row[data-tone="warn"] { background: color-mix(in srgb, var(--warn) 4%, transparent); } + +/* -------------------------------------------------------- empty state --- */ +.tc-cred-how { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); } +.tc-cred-how > div { display: flex; flex-direction: column; gap: 0.375rem; padding: 1rem 1.125rem 1.125rem; min-width: 0; } +.tc-cred-how > div + div { border-left: 1px solid var(--hairline); } +.tc-cred-how-num { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; line-height: 1.25rem; font-weight: 500; color: var(--fg); } +.tc-cred-how-num > span { width: 1.25rem; height: 1.25rem; border-radius: 50%; display: grid; place-items: center; background: var(--selected); font-size: 0.6875rem; font-weight: 600; } +.tc-cred-how p { margin: 0; font-size: 0.75rem; line-height: 1.125rem; color: var(--fg-muted); } +.tc-cred-how code { font: 400 0.6875rem/1rem var(--font-mono); color: var(--fg); background: var(--surface-sunken); border: 1px solid var(--hairline); border-radius: var(--radius-sm); + padding: 0.125rem 0.375rem; align-self: flex-start; } + +/* ------------------------------------------------------------ inspector --- */ +.tc-cred-banner { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.75rem 0.75rem 0.875rem; border-radius: var(--radius-xl); border: 1px solid var(--border); } +.tc-cred-banner > .tc-icon { flex: none; } +.tc-cred-banner > div { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; } +.tc-cred-banner strong { font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; } +.tc-cred-banner span { font-size: 0.75rem; line-height: 1.125rem; color: var(--fg-muted); } +.tc-cred-banner code { font-size: 0.75rem; color: var(--fg); } +.tc-cred-banner[data-tone="ok"] { border-color: color-mix(in srgb, var(--ok) 30%, transparent); background: color-mix(in srgb, var(--ok) 5%, transparent); } +.tc-cred-banner[data-tone="ok"] > .tc-icon { color: var(--ok); } +.tc-cred-banner[data-tone="danger"] { border-color: color-mix(in srgb, var(--danger) 30%, transparent); background: var(--danger-soft); } +.tc-cred-banner[data-tone="danger"] > .tc-icon { color: var(--danger); } +.tc-cred-banner[data-tone="danger"] strong { color: var(--danger-text); } +.tc-cred-banner[data-tone="warn"] { border-color: color-mix(in srgb, var(--warn) 32%, transparent); background: var(--warn-soft); } +.tc-cred-banner[data-tone="warn"] > .tc-icon { color: var(--warn); } +.tc-cred-banner[data-tone="warn"] strong { color: var(--warn-text); } + +.tc-pathlist.tc-cred-facts { grid-template-columns: 6.5rem minmax(0, 1fr); } +.tc-cred-facts dd .tc-spacer { flex: 1; } +.tc-cred-facts dd .tc-btn { margin: -0.25rem -0.375rem -0.25rem 0; } +.tc-cred-saved { display: inline-flex; align-items: center; gap: 0.375rem; color: var(--fg); } +.tc-cred-saved > .tc-icon { width: 0.875rem; height: 0.875rem; color: var(--fg-muted); } +.tc-cred-saved small { font-size: 0.75rem; color: var(--fg-muted); } +.tc-cred-fp { font: 400 0.75rem/1.125rem var(--font-mono); color: var(--fg); overflow-wrap: anywhere; } +.tc-cred-fp small { font-family: var(--font-sans); color: var(--fg-muted); margin-left: 0.375rem; } + +/* A command or a request, as agents will run it. */ +.tc-cred-cmds { list-style: none; margin: 0; padding: 0; } +.tc-cred-cmds li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.5rem; padding: 0.5rem 0.5rem 0.5rem 0.875rem; } +.tc-cred-cmds li + li { border-top: 1px solid var(--hairline); } +.tc-cred-cmds code { font: 400 0.75rem/1.125rem var(--font-mono); color: var(--fg); overflow-wrap: anywhere; } +.tc-cred-cmds code i { font-style: normal; color: var(--fg-subtle); } +.tc-cred-snippet { position: relative; margin: 0; padding: 0.75rem 0.875rem; border-radius: var(--radius-lg); border: 1px solid var(--hairline); background: var(--surface-sunken); + font: 400 0.75rem/1.25rem var(--font-mono); color: var(--fg); white-space: pre-wrap; overflow-wrap: anywhere; } +.tc-cred-snippet i { font-style: normal; color: var(--fg-subtle); } +.tc-cred-snippet b { font-weight: 400; color: var(--accent-text); } +.tc-cred-snippet-head { display: flex; align-items: center; gap: 0.5rem; } +.tc-cred-request { margin: 0; padding: 0.625rem 0.875rem; border-radius: var(--radius-lg); border: 1px solid var(--hairline); background: var(--surface-sunken); + font: 400 0.75rem/1.25rem var(--font-mono); color: var(--fg-muted); white-space: pre-wrap; overflow-wrap: anywhere; } +.tc-cred-request b { font-weight: 600; color: var(--fg); } +.tc-cred-request u { text-decoration: none; color: var(--fg); } +.tc-cred-request em { font-style: normal; color: var(--accent-text); } +.tc-cred-skill { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 0.625rem; padding: 0.5625rem 0.875rem; font-size: 0.8125rem; line-height: 1.25rem; } +.tc-cred-skill + .tc-cred-skill { border-top: 1px solid var(--hairline); } +.tc-cred-skill .tc-tile { width: 1.5rem; height: 1.5rem; } +.tc-cred-skill .tc-tile .tc-icon { width: 0.8125rem; height: 0.8125rem; } +.tc-cred-skill strong { font-weight: 500; } +.tc-cred-skill small { display: block; font-size: 0.75rem; line-height: 1rem; color: var(--fg-muted); } +.tc-cred-skill code { font-size: 0.6875rem; color: var(--fg-muted); } + +/* ---------------------------------------------------------------- editor --- */ +/* Desktop size only: in compact mode main's rules make it a 94dvh bottom sheet. */ +:where(:root:not([data-compact])) .tc-wizard.tc-cred-editor { width: 56rem; height: 44rem; } +.tc-cred-editor .tc-wizard-grid { grid-template-columns: minmax(0, 1fr) 20.5rem; } +.tc-wizard-rail .tc-cred-cmds code { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.tc-wizard-rail .tc-cred-fp small { display: block; margin: 2px 0 0; } +.tc-cred-editor .tc-wizard-main { gap: 1.125rem; } +.tc-cred-editor .tc-form { display: flex; flex-direction: column; gap: 1rem; } +.tc-cred-editor .tc-form-field { display: flex; flex-direction: column; gap: 0.375rem; } +.tc-cred-editor .tc-form-field > .tc-hint { margin: 0; } +.tc-cred-pair { display: grid; grid-template-columns: minmax(0, 1fr) 6.5rem; gap: 0.75rem; } +.tc-cred-pair--even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } +.tc-cred-type .tc-seg { width: 100%; } +.tc-cred-type .tc-seg button { flex: 1 1 0; justify-content: center; display: inline-flex; align-items: center; gap: 0.375rem; height: 2rem; font-size: 0.8125rem; } +.tc-cred-type .tc-seg button .tc-icon { width: 0.875rem; height: 0.875rem; } +.tc-cred-auth .tc-seg { width: 100%; } +.tc-cred-auth .tc-seg button { flex: 1 1 0; justify-content: center; display: inline-flex; align-items: center; height: 1.75rem; font-size: 0.8125rem; } +.tc-cred-locked { display: flex; align-items: center; gap: 0.5rem; height: 2.25rem; padding: 0 0.75rem; border-radius: var(--radius-md); border: 1px dashed var(--border); + background: var(--surface-sunken); font: 400 0.8125rem/1 var(--font-mono); color: var(--fg); } +.tc-cred-locked > .tc-icon { width: 0.875rem; height: 0.875rem; color: var(--fg-muted); } +.tc-cred-locked > span:last-child { margin-left: auto; font-family: var(--font-sans); font-size: 0.75rem; color: var(--fg-muted); } +.tc-cred-secret { display: flex; align-items: center; gap: 0.5rem; min-height: 2.25rem; padding: 0.25rem 0.25rem 0.25rem 0.75rem; border-radius: var(--radius-md); border: 1px solid var(--border); + background: var(--surface); font-size: 0.8125rem; } +.tc-cred-secret > .tc-icon { width: 0.875rem; height: 0.875rem; color: var(--ok); flex: none; } +.tc-cred-secret > span { flex: 1; min-width: 0; color: var(--fg); } +.tc-cred-secret small { color: var(--fg-muted); font-size: 0.75rem; } + +/* The rail: what agents will run, and the test, as the person types. */ +.tc-cred-rail-block { display: flex; flex-direction: column; gap: 0.5rem; } +.tc-cred-rail-block .tc-insp-label { font-size: 0.8125rem; min-height: 0; } +.tc-cred-test { display: flex; flex-direction: column; gap: 0.625rem; padding: 0.75rem; border-radius: var(--radius-lg); border: 1px solid var(--border); background: var(--surface); } +.tc-cred-test-line { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; line-height: 1.25rem; font-weight: 500; } +.tc-cred-test-line > .tc-icon { width: 1rem; height: 1rem; color: var(--ok); flex: none; } +.tc-cred-test-line small { margin-left: auto; font-weight: 400; font-size: 0.75rem; color: var(--fg-muted); } +.tc-cred-hostkey { display: flex; flex-direction: column; gap: 0.375rem; padding-top: 0.625rem; border-top: 1px solid var(--hairline); font-size: 0.75rem; line-height: 1.125rem; color: var(--fg-muted); } +.tc-cred-hostkey strong { color: var(--fg); font-weight: 500; font-size: 0.75rem; } +.tc-cred-hostkey code { display: block; font: 400 0.6875rem/1rem var(--font-mono); color: var(--fg); background: var(--surface-sunken); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 0.25rem 0.375rem; overflow-wrap: anywhere; } +.tc-cred-testpath { display: flex; align-items: center; gap: 0.5rem; } +.tc-cred-testpath > span { font: 600 0.75rem/1 var(--font-mono); color: var(--fg); } +.tc-cred-testpath .tc-input { height: 2rem; flex: 1; min-width: 0; } +.tc-cred-check { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8125rem; color: var(--fg); } +.tc-cred-conflict .tc-notice-body { gap: 0.375rem; } +.tc-cred-conflict-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.25rem; } +.tc-cred-conflict-actions .tc-btn { margin: 0 !important; } +.tc-cred-diffline { font: 400 0.75rem/1.125rem var(--font-mono); } +.tc-cred-diffline del { color: var(--fg-muted); } +.tc-cred-diffline ins { text-decoration: none; color: var(--warn-text); font-weight: 600; } + +/* ---------------------------------------------------------- dialogs --- */ +:where(:root:not([data-compact])) .tc-dialog.tc-cred-dialog { width: min(30rem, calc(100% - 32px)); } +.tc-cred-keys { list-style: none; margin: 0.25rem 0 0; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; } +.tc-cred-keys li { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); gap: 0.625rem; padding: 0.625rem 0.75rem; font-size: 0.75rem; line-height: 1.125rem; align-items: baseline; } +.tc-cred-keys li + li { border-top: 1px solid var(--hairline); } +.tc-cred-keys li > span { color: var(--fg-muted); } +.tc-cred-keys li[data-tone="warn"] { background: var(--warn-soft); } +.tc-cred-keys li[data-tone="warn"] > span { color: var(--warn-text); font-weight: 500; } +.tc-cred-keys code { font-size: 0.75rem; color: var(--fg); overflow-wrap: anywhere; } + +/* ------------------------------------------------- compact: the list --- */ +/* Rows become tc-prow buttons (.tc-cred-prow), MCP's phone rows, with a tile. */ +:where(:root[data-compact]) .tc-cred-toolbar { display: flex; gap: 0.5rem; align-items: center; } +:where(:root[data-compact]) .tc-cred-toolbar .tc-sk-search { flex: 1; min-width: 0; } +:where(:root[data-compact]) .tc-cred-prow { grid-template-columns: auto minmax(0, 1fr) auto; column-gap: 0.75rem; } +:where(:root[data-compact]) .tc-cred-prow > .tc-tile { grid-row: 1 / span 3; align-self: start; margin-top: 2px; } +:where(:root[data-compact]) .tc-cred-prow > .tc-icon { grid-column: 3; } +:where(:root[data-compact]) .tc-cred-prow > .tc-prow-name, :where(:root[data-compact]) .tc-cred-prow > .tc-mcp-detail, :where(:root[data-compact]) .tc-cred-prow > .tc-cred-state-line { grid-column: 2; } +:where(:root[data-compact]) .tc-cred-prow .tc-prow-name { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9375rem; } +:where(:root[data-compact]) .tc-cred-prow .tc-cred-state-line { font-size: 0.75rem; line-height: 1.125rem; margin-top: 2px; } +:where(:root[data-compact]) .tc-cred-state-line small { font-weight: 400; color: var(--fg-muted); } + +/* --------------------------------------------------------------- compact --- */ +/* main's convention (#71). The details sheet and the editor are the console's + bottom sheets in compact mode already (tc-skill-inspector, tc-wizard); only + what is particular to this page is here. */ +:where(:root[data-compact]) .tc-cred-inspector .tc-insp-head > .tc-btn:not(.tc-btn--icon) { display: none; } +:where(:root[data-compact]) .tc-cred-banner { align-items: flex-start; } +:where(:root[data-compact]) .tc-pathlist.tc-cred-facts { grid-template-columns: 5.5rem minmax(0, 1fr); } +:where(:root[data-compact]) .tc-cred-saved small { display: none; } +.tc-root[data-density="touch"] .tc-cred-editor .tc-cred-type .tc-seg button { height: 2.5rem; font-size: 0.9375rem; } + +/* Credentials owns its lane, including when Settings gives it less room than + the browser viewport. Long names and metadata never steal action space. */ +.tc-credentials-library { margin-top: -0.75rem; display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; container: credentials / inline-size; } +.tc-cred-toolbar .tc-sk-search { min-width: 0; } +.tc-cred-toolbar .tc-btn[aria-pressed="true"] { background: var(--warn-soft); color: var(--warn-text); border-color: color-mix(in srgb, var(--warn) 40%, transparent); } +.tc-cred-toolbar .tc-btn > .tc-dot { margin-right: 0.125rem; } +.tc-cred-name > button { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; } +.tc-cred-name > .tc-badge { flex: none; } +.tc-cred-main .tc-mcp-detail > code { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: inherit; } +.tc-cred-meta > .tc-keys { max-width: 100%; min-width: 0; } +.tc-cred-meta .tc-key { max-width: 100%; overflow: hidden; text-overflow: ellipsis; } +.tc-cred-meta .tc-key .tc-icon { flex: none; } +.tc-cred-meta > .tc-cred-used { flex: 1 1 10rem; } +.tc-cred-row[aria-busy="true"] .tc-cred-main { opacity: 0.65; } +.tc-cred-storage { align-items: flex-start; line-height: 1.125rem; } +.tc-cred-storage > .tc-icon { flex: none; margin-top: 1px; } +.tc-cred-how { border-top: 1px solid var(--hairline); } +.tc-cred-skeleton-line { height: 0.875rem; width: min(18rem, 70%); } +.tc-cred-usage-warning { display: flex; align-items: flex-start; gap: 0.375rem; } +.tc-cred-banner > .tc-cred-banner-actions { flex: none; flex-direction: row; gap: 0.375rem; flex-wrap: wrap; justify-content: flex-end; } +.tc-cred-inspector .tc-insp-head > .tc-btn:not(.tc-btn--icon) { flex: none; } +.tc-cred-inspector .tc-insp-body { gap: 1.75rem; } +.tc-cred-inspector .tc-insp-label > .tc-hint { text-align: right; font-size: 0.6875rem; } +.tc-cred-inspector .tc-cred-saved { flex-wrap: wrap; } +.tc-cred-inspector .tc-cred-facts dd > code { min-width: 0; overflow-wrap: anywhere; } +.tc-cred-editor .tc-cred-reveal { position: relative; display: flex; align-items: center; } +.tc-cred-reveal > .tc-input { padding-right: 2.5rem; } +.tc-cred-reveal > .tc-reveal { position: absolute; right: 0.375rem; } +.tc-cred-keep { align-self: flex-start; padding: 0; min-height: 1.25rem; } +.tc-cred-editor .tc-cred-hostkey--first { border-top: 0; padding-top: 0; } +.tc-cred-test-line[data-tone="danger"], .tc-cred-test-line[data-tone="danger"] > .tc-icon { color: var(--danger-text); } +.tc-cred-test-line[data-tone="warn"], .tc-cred-test-line[data-tone="warn"] > .tc-icon { color: var(--warn-text); } +.tc-cred-editor-error { flex: none; padding: 0.625rem 1.25rem; border-top: 1px solid var(--hairline); } +.tc-cred-editor .tc-wizard-rail-toggle > code { font-size: 0.75rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; } +.tc-cred-editor .tc-wizard-rail-toggle > .tc-icon { flex: none; } +.tc-cred-inspector .tc-cred-request, .tc-cred-editor .tc-cred-request { max-width: 100%; } +@container credentials (max-width: 780px) { + .tc-cred-list > .tc-row { grid-template-columns: auto minmax(0, 1fr) 12rem 7.25rem; column-gap: 0.625rem; } + .tc-cred-meta { gap: 0.25rem 0.75rem; } +} +@container credentials (max-width: 660px) { + .tc-cred-list > .tc-row { grid-template-columns: auto minmax(0, 1fr) auto; } + .tc-cred-list > .tc-row > .tc-cred-state { grid-column: 2; grid-row: 2; margin-top: 0.25rem; } + .tc-cred-list > .tc-row > .tc-row-actions { grid-column: 3; grid-row: 1 / span 2; } +} +:where(:root[data-compact]) .tc-cred-toolbar .tc-sk-search { flex: 1 1 calc(100% - 3.5rem); order: 1; } +:where(:root[data-compact]) .tc-cred-toolbar > .tc-spacer { display: none; } +:where(:root[data-compact]) .tc-cred-toolbar .tc-cred-add { order: 2; flex: none; width: var(--touch); height: var(--touch); padding: 0; } +:where(:root[data-compact]) .tc-cred-add > span { display: none; } +:where(:root[data-compact]) .tc-cred-toolbar .tc-sk-attention { order: 3; } +:where(:root[data-compact]) .tc-cred-prow { width: 100%; appearance: none; border: 0; background: transparent; font: inherit; text-align: left; } +:where(:root[data-compact]) .tc-cred-prow + .tc-cred-prow { border-top: 1px solid var(--hairline); } +:where(:root[data-compact]) .tc-cred-prow .tc-prow-name { min-width: 0; overflow-wrap: anywhere; flex-wrap: wrap; gap: 0.25rem 0.5rem; } +:where(:root[data-compact]) .tc-cred-prow .tc-mcp-detail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; } +:where(:root[data-compact]) .tc-cred-prow .tc-cred-state-line > span:last-child { white-space: normal; } +:where(:root[data-compact]) .tc-cred-how { grid-template-columns: minmax(0, 1fr); } +:where(:root[data-compact]) .tc-cred-how > div + div { border-left: 0; border-top: 1px solid var(--hairline); } +:where(:root[data-compact]) .tc-cred-banner { flex-wrap: wrap; } +:where(:root[data-compact]) .tc-cred-banner > .tc-cred-banner-actions { width: 100%; padding-left: 1.75rem; justify-content: flex-start; } +:where(:root[data-compact]) .tc-cred-editor .tc-wizard-foot > .tc-wizard-keyboard { display: none; } +:where(:root[data-compact]) .tc-cred-editor .tc-wizard-grid { grid-template-columns: minmax(0, 1fr); } +:where(:root[data-compact]) .tc-cred-test .tc-cred-check { min-height: var(--touch); } +.tc-root[data-density="touch"] :is(.tc-cred-inspector, .tc-cred-editor, .tc-cred-dialog) .tc-btn { min-height: var(--touch); } +.tc-cred-skel { grid-template-columns: auto minmax(0, 1fr); min-height: 4.5rem; height: auto; padding: 1rem; } +/* The handoff puts the toolbar close to the head and leaves a full row gap + before the list. Only this feature owns the adjustment. */ +.tc-credentials-library:has(> .tc-cred-toolbar) { gap: 1.25rem; } +.tc-cred-state-line[data-tone="muted"] > .tc-dot { background: var(--fg-subtle); } +.tc-cred-hostkey > .tc-cred-fp { word-break: break-all; } +.tc-cred-hostkey + .tc-cred-test-line { padding-top: 0.625rem; border-top: 1px solid var(--hairline); } +.tc-cred-compare > summary { color: var(--fg-muted); cursor: pointer; min-height: 2.75rem; align-content: center; } +.tc-cred-compare > code { margin-top: 0.25rem; } +:where(:root:not([data-compact])) .tc-layer--sheet > .tc-cred-inspector { width: min(32.5rem, calc(100dvw - 1rem)); } +.tc-cred-facts .tc-cred-fp { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; } +.tc-cred-key-type { color: var(--fg-muted); font-size: 0.6875rem; } +.tc-cred-fingerprint { display: block; font-size: 0.6875rem; line-height: 1rem; word-break: break-all; } +.tc-cred-facts .tc-cred-fp small { display: block; margin: 0; } +.tc-cred-snippet-detail > summary { font-size: 0.75rem; color: var(--fg-muted); cursor: pointer; } +.tc-cred-snippet-detail > .tc-cred-snippet { margin-top: 0.5rem; } +:where(:root[data-compact]) .tc-cred-snippet-detail > summary { min-height: 2.75rem; align-content: center; } + +.tc-cred-inspector .tc-insp-title h2 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tc-cred-skill > div { min-width: 0; overflow-wrap: anywhere; } +.tc-cred-dialog .tc-dialog-title, .tc-cred-editor .tc-sheet-title { overflow-wrap: anywhere; } +.tc-cred-result { display: flex; flex-direction: column; gap: 1.25rem; } +.tc-cred-result > .tc-cred-banner-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; } +:where(:root[data-compact]) .tc-layer--sheet > .tc-cred-inspector { max-height: 84dvh; } diff --git a/docker/setup/credentials.mjs b/docker/setup/credentials.mjs index 978a859f..9e90d945 100644 --- a/docker/setup/credentials.mjs +++ b/docker/setup/credentials.mjs @@ -129,7 +129,7 @@ export function createCredentialStore({ directory = credentialDirectory(), readO if (create && previous) throw new CredentialError('That name is already taken. Choose another credential name.', 409, 'taken'); if (!create) await current(data, credential.id, expected); if (!previous && data.profiles.length >= 64) throw new CredentialError('Save at most 64 credentials.'); - const normalized = normalize(credential, previous), at = now(); + const normalized = normalize(credential, previous), at = new Date(Math.max(clock(), previous ? Date.parse(previous.updatedAt) + 1 : 0)).toISOString(); const saved = { ...normalized, createdAt: previous?.createdAt || at, updatedAt: at, secretChangedAt: !previous || normalized.secret !== previous.secret ? at : previous.secretChangedAt, revision: revision() }; const metadata = await state.read(data.profiles), keys = new Map(); const changed = !previous || JSON.stringify(normalize(previous)) !== JSON.stringify(normalized); diff --git a/docker/setup/credentials/service.mjs b/docker/setup/credentials/service.mjs index 76d254f1..cce734eb 100644 --- a/docker/setup/credentials/service.mjs +++ b/docker/setup/credentials/service.mjs @@ -26,7 +26,7 @@ export function createCredentialsService({ store = createCredentialStore(), usag const trustSaved = async (id, expected, signal, revision) => { const profile = await store.public(id); if (profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); - if (revision !== undefined && revision !== profile.revision) throw new CredentialError('This credential changed before its key could be trusted.', 409, 'changed'); + if (revision !== undefined && revision !== profile.revision) throw new CredentialError('This credential changed before its key could be reviewed. Read the current details first.', 409, 'changed', { current: profile }); const scanned = await scan(profile, signal); if (!scanned.ok) return { ok: false, code: scanned.code }; if (scanned.key.fingerprint !== expected) throw new CredentialError('The server presented another key. Review its new fingerprint before trusting it.', 409, 'key-changed', { presented: scanned.hostKey.presented }); @@ -82,10 +82,11 @@ export function createCredentialsService({ store = createCredentialStore(), usag if (route === '/credentials/remove') return { ok: true, ...await store.remove(input) }; if (route === '/credentials/forget-host-key') { await store.forget(input.id); return { ok: true }; } if (route === '/credentials/test') return network(signal => testInput(input, signal)); - if (route === '/credentials/trust') { const expected = validTrust({ fingerprint: input.fingerprint }); return network(signal => trustSaved(input.id, expected, signal)); } + if (route === '/credentials/trust') { const expected = validTrust({ fingerprint: input.fingerprint }); return network(signal => trustSaved(input.id, expected, signal, input.revision)); } if (route === '/credentials/scan') return network(async signal => { const profile = input.id === undefined ? { host: input.host, port: input.port } : await store.public(input.id); if (input.id !== undefined && profile.type !== 'ssh') throw new CredentialError('Choose an SSH credential.'); + if (input.revision !== undefined && input.revision !== profile.revision) throw new CredentialError('This credential changed before its key could be reviewed. Read the current details first.', 409, 'changed', { current: profile }); const started = clock(), scanned = await scan(profile, signal); return scanned.ok ? { ok: true, hostKey: scanned.hostKey } : { ok: true, result: { ...scanned, ms: clock() - started } }; }); diff --git a/docker/setup/page.mjs b/docker/setup/page.mjs index 8261409d..6e614460 100644 --- a/docker/setup/page.mjs +++ b/docker/setup/page.mjs @@ -46,6 +46,10 @@ export const CONSOLE_SCRIPTS = [ "client/mcp-inspector.js", "client/mcp-editor.js", "client/mcp.js", + "client/credential-model.js", + "client/credential-inspector.js", + "client/credential-editor.js", + "client/credential-dialogs.js", "client/credentials.js", "client/files-model.js", "client/files-editor.js", diff --git a/docker/setup/server.mjs b/docker/setup/server.mjs index e6842aed..0e91d39e 100644 --- a/docker/setup/server.mjs +++ b/docker/setup/server.mjs @@ -535,9 +535,10 @@ const skillsService = createSkillsService({ home: CONTEXT_HOME, env: process.env const mcpService = createMcpService({ home: CONTEXT_HOME, env: process.env, baseDir: STATE_DIR, io: await contextFs(), }); +let credentialInstalled = null; const credentials = createCredentialsService({ store: credentialStore, usage: createCredentialUsage({ home: CONTEXT_HOME, baseDir: STATE_DIR, env: process.env, io: await contextFs(), - installed: async () => ((await harnessCache.snapshotCheap()).harnesses || []).filter(row => row.installed).map(row => row.id), + installed: async () => credentialInstalled || [...((await harnessCache.snapshotCheap()).harnesses || []).filter(row => row.installed).map(row => row.id), 'native-provider-not-yet-reported'], }) }); let filesPromise, filesInstance, filesPayloads = 0; const loadFiles = () => filesPromise ??= loadStorage().then(storage => createFilesService({ @@ -847,6 +848,7 @@ const status = async () => { // console (the row says so); while T3 itself is down the page already says. const t3Agents = antigravityRow && (antigravityRow.available || (!antigravityRow.reachable && server?.ok)) ? [antigravityRow] : []; const harnesses = harnessSnap?.harnesses ?? []; + credentialInstalled = [...harnesses, ...t3Agents].filter(row => row.installed).map(row => row.id); const verdicts = new Map((scmSnap?.harnesses ?? []).map((row) => [row.id, row.auth])); const sourceControl = (toolchainSnap?.sourceControl ?? []).map((row) => ({ ...row, auth: verdicts.get(row.id) ?? null })); knownSourceControl.clear(); diff --git a/docker/t3-client/setup-bridge.js b/docker/t3-client/setup-bridge.js index 0c8fa45d..70557e87 100644 --- a/docker/t3-client/setup-bridge.js +++ b/docker/t3-client/setup-bridge.js @@ -146,6 +146,7 @@ { id: 'agents', route: 'agents', title: 'Agents', meta: 'Setup · sign in, install and update', terms: [] }, { id: 'context', route: 'instructions', title: 'Instructions & skills', meta: 'Setup · global AGENTS.md and skills', terms: ['agents.md global instructions', 'context', 'skills'] }, { id: 'mcp', route: 'mcp', title: 'MCP servers', meta: 'Setup · shared definitions and provider configuration', terms: ['mcp tools servers'] }, + { id: 'credentials', route: 'credentials', title: 'Credentials', meta: 'Setup · SSH and API logins agents use by name', terms: ['ssh', 'api key', 'token', 'password', 'secret', 'server credentials'] }, { id: 'pair', route: 'access', title: 'Pair a device', meta: 'Setup · Access', terms: ['devices', 'pairing'] }, { id: 'toolchains', route: 'toolchains', title: 'Toolchains', meta: 'Setup · Go, Rust, Bun, Deno, uv and any mise tool', terms: [] }, { id: 'sourcecontrol', route: 'sourcecontrol', title: 'Source control', meta: 'Setup · sign in to GitHub, GitLab, Forgejo, Gitea and Azure DevOps', terms: ['codeberg', 'gh glab fj tea az'] }, diff --git a/scripts/console-preview.mjs b/scripts/console-preview.mjs index 55d9d714..179966b4 100644 --- a/scripts/console-preview.mjs +++ b/scripts/console-preview.mjs @@ -11,6 +11,8 @@ const { createSkillsFixtures } = require('./lib/skills-fixtures.cjs'); const { createStorageFixtures } = require('./lib/storage-fixtures.cjs'); const { createMcpFixtures } = require('./lib/mcp-fixtures.cjs'); const { createFilesFixtures } = require('./lib/files-fixtures.cjs'); +const { createCredentialsFixtures } = require('./lib/credentials-fixtures.cjs'); +const credentials = createCredentialsFixtures(); const files = createFilesFixtures(); const mcp = createMcpFixtures(); const api = createSkillsFixtures(); @@ -30,10 +32,9 @@ http.createServer(async (req, res) => { let input; try { input = url.pathname.endsWith('/files/upload/chunk')?Buffer.concat(chunks):chunks.length ? JSON.parse(Buffer.concat(chunks)) : {}; } catch { res.writeHead(400); res.end(); return; } - const result = await files.respond(req.method, url, input) || await mcp.respond(req.method, url, input) || storage.respond(req.method, url, input) || api.respond(req.method, url, input) || (url.pathname.endsWith('/status') ? { body: { ...statusFor('skills'), storage: storage.status(), context: { ...statusFor('skills').context, mcp: mcp.status() } } } + const result = await credentials.respond(req.method, url, input) || await files.respond(req.method, url, input) || await mcp.respond(req.method, url, input) || storage.respond(req.method, url, input) || api.respond(req.method, url, input) || (url.pathname.endsWith('/status') ? { body: { ...statusFor('skills'), credentials: credentials.status(), storage: storage.status(), context: { ...statusFor('skills').context, mcp: mcp.status() } } } : url.pathname.endsWith('/ports') ? { body: portsFor('ready') } : url.pathname.endsWith('/providers') ? { body: fixture('providers.json') } - : url.pathname.endsWith('/credentials') && req.method === 'GET' ? { body: fixture('credentials.json') } : { status: 404, body: { ok: false, error: 'This is a read-only fixture preview. No live API is connected.' } }); if (result.body?.etag && req.headers['if-none-match'] === result.body.etag) { res.writeHead(304, { ETag: result.body.etag }); res.end(); return; } res.writeHead(result.status || 200, { 'content-type': 'application/json', 'cache-control': 'no-store', ...result.headers }); diff --git a/scripts/credentials-ui-audit.mjs b/scripts/credentials-ui-audit.mjs index b843b96b..65ed63f8 100644 --- a/scripts/credentials-ui-audit.mjs +++ b/scripts/credentials-ui-audit.mjs @@ -1,152 +1,249 @@ #!/usr/bin/env node -// Real credential API + disposable home; no real server or credential is used. +// Real Setup API, private disposable home and loopback API. SSH handshakes in +// the trust-dialog cases are intercepted; no external service is contacted. import assert from 'node:assert/strict'; import * as fs from 'node:fs/promises'; import path from 'node:path'; +import { once } from 'node:events'; +import { createServer } from 'node:http'; import { createRequire } from 'node:module'; import { credentialsFixture } from '../tests/fixtures/credentials.mjs'; +import { createCredentialStore } from '../docker/setup/credentials.mjs'; +import { credentialKey } from '../tests/fixtures/credential-keys.mjs'; const require = createRequire(import.meta.url); let chromium; try { ({ chromium } = require('playwright')); } catch { ({ chromium } = require('playwright-core')); } const { statusFor, portsFor, fixture, framed } = require('./lib/console-fixtures.cjs'); const output = process.env.T3_CREDENTIALS_UI_OUTPUT || '/tmp/t3-credentials-ui'; await fs.mkdir(output, { recursive: true }); -const f = await credentialsFixture(); +const f = await credentialsFixture(), directory = path.join(f.env.T3CODE_HOME, 'server-credentials'); +let clock = Date.now(); const store = createCredentialStore({ directory, clock: () => clock }); +const secret = 'fixture-browser-password-123', token = 'fixture-browser-token-456', replacement = 'fixture-replacement-private-789'; +const loopback = createServer((req, res) => { res.writeHead(200, { 'content-type': 'application/json' }); res.end('{"ok":true}'); }); +loopback.listen(0, '127.0.0.1'); await once(loopback, 'listening'); +const localApi = 'http://127.0.0.1:' + loopback.address().port + '/v1/'; const browser = await chromium.launch({ executablePath: process.env.CHROME_PATH || '/usr/bin/chromium', args: ['--no-sandbox'] }); -const secret = 'fixture-browser-password-123', token = 'fixture-browser-token-456'; -try { - for (const theme of ['light', 'dark']) for (const [width, height, embedded] of [[360, 720], [390, 844], [820, 900], [1280, 900], [1198, 878, true]].filter(size => !process.env.T3_CREDENTIALS_UI_WIDTH || size[0] === Number(process.env.T3_CREDENTIALS_UI_WIDTH))) { - console.log(`Checking ${theme} ${width}x${height}${embedded ? ' embedded' : ''}`); - for (const profile of (await (await f.request('/credentials')).json()).profiles) { - const current = await (await f.request('/credentials')).json(); - assert.equal((await f.request('/credentials/remove', { id: profile.id, revision: current.revision })).status, 200); +let checks = 0; +const check = (condition, message) => { assert.ok(condition, message); checks++; }; +const variants = [[1280, 900, 'standalone'], [1024, 768, 'standalone'], [744, 900, 'standalone'], [390, 844, 'standalone'], [360, 720, 'standalone'], [1198, 878, 'embedded'], [480, 760, 'tab'], [639, 800, 'tab'], [640, 800, 'tab'], [704, 800, 'tab'], [1040, 820, 'tab']]; +const themes = (process.env.T3_CREDENTIALS_UI_THEMES || 'light,dark').split(','); +const requestedWidths = (process.env.T3_CREDENTIALS_UI_WIDTHS || process.env.T3_CREDENTIALS_UI_WIDTH || '').split(',').filter(Boolean).map(Number); +const selected = variants.filter(([width]) => !requestedWidths.length || requestedWidths.includes(width)); +async function seed() { + for (const row of (await store.list()).credentials) await store.remove({ id: row.id, revision: row.revision }); + const key = credentialKey(), next = credentialKey(); + for (const profile of fixture('credentials.json').credentials) { + clock = Date.parse('2026-10-26T18:04:11Z'); + const saved = (await store.save({ create: true, credential: { ...profile, secret: profile.type === 'ssh' ? secret : token } })).credential; + if (profile.type === 'ssh') await store.trust({ id: profile.id, revision: saved.revision, key }); + if (profile.test) { + clock = Date.now() - (profile.id === 'build-server' ? 120000 : profile.id === 'home-assistant' ? 86400000 : 3600000); + const result = profile.test.code === 'host-key-changed' ? { ...profile.test, detail: { trusted: { type: key.type, fingerprint: key.fingerprint }, presented: { type: next.type, fingerprint: next.fingerprint } } } : profile.test; + await store.recordTest({ id: profile.id, revision: saved.revision, hostFingerprint: profile.type === 'ssh' ? key.fingerprint : undefined, result }); + } + } + clock = Date.now(); return { key, next }; +} +async function geometry(target, width, height, label) { + const problems = await target.evaluate(({ width, height }) => { + const errors = [], rect = el => { const r = el.getBoundingClientRect(); return { x: r.x, y: r.y, width: r.width, height: r.height, right: r.right, bottom: r.bottom }; }; + if (document.documentElement.scrollWidth > innerWidth + 1) errors.push('document overflows'); + for (const panel of document.querySelectorAll('.tc-cred-editor,.tc-cred-inspector,.tc-cred-dialog')) { + const r = rect(panel); if (r.x < -1 || r.y < -1 || r.right > width + 1 || r.bottom > height + 1) errors.push('panel outside viewport: ' + JSON.stringify(r)); + const foot = panel.querySelector('.tc-wizard-foot'); if (foot && rect(foot).bottom > height + 1) errors.push('save footer outside viewport'); + if (panel.scrollWidth > panel.clientWidth + 2) errors.push('panel content overflows'); } + for (const row of document.querySelectorAll('.tc-cred-row')) { + const parts = [...row.children].map(rect).filter(r => r.width > 0 && r.height > 0); + for (let i = 0; i < parts.length; i++) for (let j = i + 1; j < parts.length; j++) if (Math.min(parts[i].right, parts[j].right) - Math.max(parts[i].x, parts[j].x) > 1 && Math.min(parts[i].bottom, parts[j].bottom) - Math.max(parts[i].y, parts[j].y) > 1) errors.push('row columns overlap'); + } + return errors; + }, { width, height }); + assert.deepEqual(problems, [], label); checks++; +} +try { + for (const theme of themes) for (const [width, height, mode] of selected) { + console.log('Checking ' + theme + ' ' + width + ' ' + mode); + const keys = await seed(); const page = await browser.newPage({ viewport: { width, height }, colorScheme: theme, reducedMotion: 'reduce' }); - const errors = [], responses = []; page.on('pageerror', error => errors.push(error.message)); - page.on('response', response => { if (/\/credentials(?:\/|$)/.test(new URL(response.url()).pathname)) responses.push(response.text().catch(() => '')); }); + const pageErrors = [], responseBodies = []; + page.on('pageerror', error => pageErrors.push(error.message)); + page.on('response', response => { if (/\/credentials(?:\/|$)/.test(new URL(response.url()).pathname)) responseBodies.push(response.text().catch(() => '')); }); await page.addInitScript(value => localStorage.setItem('t3-console-theme', value), theme); - await page.addInitScript(() => { - Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { - writeText: async text => { window.__copiedSkillCommand = text; }, - } }); - }); - await page.route('**/*', route => { + await page.addInitScript(() => Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { writeText: async value => { window.__credentialCopy = value; } } })); + await page.route('**/*', async route => { const url = new URL(route.request().url()); - if (url.pathname.endsWith('/status')) return route.fulfill({ json: statusFor('ready') }); + if (url.pathname.endsWith('/status')) return route.fulfill({ json: { ...statusFor('ready'), credentials: await store.summary() } }); if (url.pathname.endsWith('/providers')) return route.fulfill({ json: fixture('providers.json') }); if (url.pathname.endsWith('/ports')) return route.fulfill({ json: portsFor('ready') }); return route.continue(); }); - const url = f.base + '/' + (embedded ? '?embed=t3&theme=' + theme : '') + '#credentials'; + const embedded = mode !== 'standalone', url = f.base + '/' + (embedded ? '?embed=t3&theme=' + theme + (mode === 'tab' ? '&host=tab&layout=wide' : '') : '') + '#credentials'; const target = embedded ? await framed(page, url) : (await page.goto(url), page); - await target.getByLabel('Setup key', { exact: true }).fill('credential-fixture-key'); - await target.getByRole('button', { name: 'Unlock', exact: true }).click(); - await target.getByText('Save a connection once', { exact: true }).waitFor(); - const capture = step => page.screenshot({ path: path.join(output, `${theme}-${width}${embedded ? '-embedded' : ''}-${step}.png`), fullPage: true }); - await capture('empty'); - const dialog = target.getByRole('dialog'); - const add = async (id, label, type = 'ssh') => { - await target.getByRole('button', { name: 'Add connection', exact: true }).first().click(); - await dialog.waitFor(); await target.getByLabel('Name', { exact: true }).fill(label); - await target.getByLabel('Connection ID', { exact: true }).fill(id); - await target.getByLabel('Connection type').selectOption(type); - if (type === 'ssh') { await target.getByLabel('Host', { exact: true }).fill('192.0.2.10'); await target.getByLabel('Username', { exact: true }).fill(id === 'build-server' ? 'deploy' : 'root'); } - else { - await target.getByLabel('API base URL').fill('https://api.example.com/v1/'); - await target.getByLabel('Authentication', { exact: true }).selectOption('header'); - await target.getByLabel('Header name', { exact: true }).fill('X-API-Key'); - await target.getByLabel('Test path (optional)', { exact: true }).fill('account'); + const capture = name => page.screenshot({ path: path.join(output, `${theme}-${width}-${mode}-${name}.png`), fullPage: true }); + await target.getByLabel('Setup key', { exact: true }).fill('credential-fixture-key'); await target.getByRole('button', { name: 'Unlock', exact: true }).click(); + await target.locator('[data-cred-action="inspect"][data-id="build-server"]').waitFor(); + await geometry(target, width, height, 'list'); await capture('list'); + const search = target.getByRole('searchbox', { name: 'Search credentials' }); + await search.fill('X-API-Key'); check(await target.locator('.tc-cred-row,.tc-cred-prow').count() === 1, 'search matches secret kind'); await search.fill(''); + await target.getByRole('button', { name: 'Needs attention 2', exact: true }).click(); check(await target.locator('.tc-cred-row,.tc-cred-prow').count() === 2, 'attention filter'); + await target.getByRole('button', { name: 'Needs attention 2', exact: true }).click(); + await target.locator('[data-cred-action="inspect"][data-id="project-api"]').click(); + const inspector = target.locator('.tc-cred-inspector'); await inspector.waitFor(); await geometry(target, width, height, 'inspector'); await capture('inspect-api'); + check((await inspector.locator('.tc-cred-request').textContent()).includes('••••••••'), 'request has mask'); + await inspector.getByRole('button', { name: 'Copy snippet', exact: true }).click(); + check((await target.evaluate(() => window.__credentialCopy)).includes('t3-api project-api'), 'snippet uses name'); + await inspector.getByRole('button', { name: 'Close credential details' }).click(); + const edit = async id => { + await target.locator('[data-cred-action="inspect"][data-id="' + id + '"]').click(); + const details = target.locator('.tc-cred-inspector'); + if (await details.locator('[data-cred-inspect="edit"]').isVisible()) await details.locator('[data-cred-inspect="edit"]').click(); + else { await details.locator('[data-cred-inspect="menu"]').click(); await target.getByRole('menuitem', { name: 'Edit…', exact: true }).click(); } + await target.locator('.tc-cred-editor').waitFor(); + }; + await edit('build-server'); + let editor = target.locator('.tc-cred-editor'); + check(await editor.locator('#cred-id').count() === 0, 'saved name is locked'); + await editor.getByRole('button', { name: 'Replace…', exact: true }).click(); + check(await editor.locator('#cred-secret').inputValue() === '', 'replacement starts empty'); + await editor.locator('#cred-secret').fill(replacement); await editor.getByRole('button', { name: 'Show newly typed password' }).click(); + check(await editor.locator('#cred-secret').getAttribute('type') === 'text', 'reveal only typed password'); + check(!(await target.content()).includes(replacement), 'typed secret absent from markup'); + await geometry(target, width, height, 'editor'); await capture('edit-ssh'); + const current = await store.public('build-server'); + await store.save({ credential: { ...current, username: 'deploy-next' }, revision: current.revision }); + await editor.locator('[data-cred-editor="save"]').click(); await editor.locator('#cred-conflict').waitFor(); + check((await editor.locator('#cred-conflict').innerText()).includes('deploy-next'), 'conflict explains field change'); + check(await editor.locator('#cred-secret').inputValue() === replacement, 'conflict keeps draft secret'); await capture('conflict'); + await editor.getByRole('button', { name: 'Use theirs', exact: true }).click(); + check(await editor.locator('#cred-secret').inputValue() === replacement, 'use theirs keeps typed secret when saved secret unchanged'); + const newer = await store.public('build-server'); + await store.save({ credential: { ...newer, secret: 'external-replacement-synthetic' }, revision: newer.revision }); + await editor.locator('[data-cred-editor="save"]').click(); await editor.locator('#cred-conflict').waitFor(); + await editor.getByRole('button', { name: 'Use theirs', exact: true }).click(); + check(await editor.locator('#cred-secret').count() === 0, 'use theirs clears typed secret if theirs replaced it'); + await editor.getByRole('button', { name: 'Close credential editor' }).click(); await editor.waitFor({ state: 'hidden' }); + await edit('build-server'); editor = target.locator('.tc-cred-editor'); + await editor.getByLabel('Username', { exact: true }).fill('draft-user'); + const latest = await store.public('build-server'); + await store.save({ credential: { ...latest, username: 'edited-elsewhere' }, revision: latest.revision }); + await editor.locator('[data-cred-editor="save"]').click(); await editor.locator('#cred-conflict').waitFor(); + await editor.getByRole('button', { name: 'Keep mine', exact: true }).click(); await editor.waitFor({ state: 'hidden' }); + check((await store.forUse('build-server')).username === 'draft-user', 'Keep mine saves the draft against the reviewed revision'); + check((await store.forUse('build-server')).secret === 'external-replacement-synthetic', 'Keep mine without a replacement keeps the current saved secret'); + await target.getByRole('button', { name: 'Add credential', exact: true }).click(); editor = target.locator('.tc-cred-editor'); + await editor.getByLabel('Name', { exact: true }).fill('Fixture Login'); + check(await editor.getByLabel('Name', { exact: true }).inputValue() === 'fixture-login', 'name normalized as typed'); + await editor.getByLabel('Host', { exact: true }).fill('192.0.2.30'); await editor.getByLabel('Username', { exact: true }).fill('deploy'); await editor.locator('#cred-secret').fill(secret); + await editor.getByRole('button', { name: 'HTTP API', exact: true }).click(); + check(await editor.getByLabel('Name', { exact: true }).inputValue() === 'fixture-login', 'type switch retains name'); check(await editor.locator('#cred-secret').inputValue() === '', 'type switch clears password'); + await editor.getByLabel('Base URL', { exact: true }).fill(localApi); await editor.getByRole('button', { name: 'Header', exact: true }).click(); + await editor.getByLabel('Header name', { exact: true }).fill('X-API-Key'); await editor.locator('#cred-secret').fill(token); + await editor.getByRole('button', { name: 'Query parameter', exact: true }).click(); check(await editor.locator('#cred-secret').inputValue() === token, 'auth switch retains newly typed key'); + await editor.getByRole('button', { name: 'Header', exact: true }).click(); await editor.getByLabel('GET test path (optional)', { exact: true }).fill('account'); + const beforeTest = await store.list(); + await editor.locator('[data-cred-editor="test"]').click(); await editor.getByText('Connected · HTTP 200', { exact: true }).waitFor(); + check(JSON.stringify(await store.list()) === JSON.stringify(beforeTest), 'draft testing writes nothing'); + if (width < (mode === 'tab' ? 640 : 1024)) { + const feedback = await editor.locator('.tc-cred-test-line').evaluate(el => { const r = el.getBoundingClientRect(), foot = document.querySelector('.tc-cred-editor .tc-wizard-foot').getBoundingClientRect(); return { top: r.top, bottom: r.bottom, actions: foot.top }; }); + await capture('draft-tested'); + check(feedback.top >= -1 && feedback.bottom <= feedback.actions + 1, 'phone test feedback is visible above pinned actions: ' + JSON.stringify(feedback)); + } + // Delay the actual write. Enter/Escape and a second submit cannot duplicate it. + let release, arrived, saves = 0; const gate = new Promise(resolve => { release = resolve; }), arrival = new Promise(resolve => { arrived = resolve; }); + const hold = async route => { saves++; arrived(); await gate; await route.continue(); }; + await page.route('**/credentials/create', hold); await editor.locator('[data-cred-editor="save"]').click(); await arrival; + await editor.dispatchEvent('submit'); await page.keyboard.press('Escape'); + check(await editor.locator('#cred-secret').isDisabled(), 'fields disabled while saving'); check(await editor.locator('[data-cred-editor="close"]').first().isDisabled(), 'cannot close an unsettled save'); + release(); await editor.waitFor({ state: 'hidden' }); await page.unroute('**/credentials/create', hold); check(saves === 1, 'save submitted exactly once'); + await target.locator('[data-cred-action="inspect"][data-id="fixture-login"]').waitFor(); + check((await store.forUse('fixture-login')).secret === token, 'real API saved the new key'); + await edit('fixture-login'); editor = target.locator('.tc-cred-editor'); + await editor.getByLabel('Base URL', { exact: true }).fill(localApi + 'changed/'); + await editor.getByRole('button', { name: 'Close credential editor' }).click(); + await target.getByRole('alertdialog').getByRole('button', { name: 'Cancel', exact: true }).click(); check(await editor.isVisible(), 'cancel discard keeps draft'); + await editor.getByRole('button', { name: 'Close credential editor' }).click(); await target.getByRole('alertdialog').getByRole('button', { name: 'Discard changes', exact: true }).click(); await editor.waitFor({ state: 'hidden' }); + // Review a key that changes again while the person decides. No SSH auth. + await target.locator('[data-cred-action="inspect"][data-id="staging-server"]').click(); + const presented = { type: keys.next.type, fingerprint: keys.next.fingerprint }, third = credentialKey(); + await page.route('**/credentials/scan', route => route.fulfill({ json: { ok: true, hostKey: { state: 'changed', trusted: { type: keys.key.type, fingerprint: keys.key.fingerprint }, presented } } })); + let trustCalls = 0; + await page.route('**/credentials/trust', async route => { + trustCalls++; + if (trustCalls === 1) return route.fulfill({ status: 409, json: { ok: false, code: 'key-changed', error: 'The key changed again.', presented: { type: third.type, fingerprint: third.fingerprint } } }); + check(route.request().postDataJSON().fingerprint === third.fingerprint, 'trust uses the new displayed fingerprint'); + const saved = await store.public('staging-server'); + if (trustCalls === 2) { + const current = (await store.save({ credential: { ...saved, host: '192.0.2.31' }, revision: saved.revision })).credential; + return route.fulfill({ status: 409, json: { ok: false, code: 'changed', error: 'The host was edited elsewhere.', current } }); } - await target.locator('#credential-secret').fill(type === 'ssh' ? secret : token); - await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); - await dialog.waitFor({ state: 'hidden' }); await target.locator(`[data-key="credential-${id}"]`).waitFor(); + check(route.request().postDataJSON().revision === saved.revision, 'trust binds the refreshed connection revision'); + await store.trust({ id: saved.id, revision: saved.revision, key: third }); + return route.fulfill({ json: { ok: true, hostKey: (await store.public(saved.id)).hostKey } }); + }); + await target.locator('.tc-cred-inspector').getByRole('button', { name: 'Review…', exact: true }).click(); + const trustDialog = target.locator('.tc-cred-dialog'); await trustDialog.getByText(presented.fingerprint, { exact: false }).waitFor(); + await trustDialog.getByRole('button', { name: 'Trust new key', exact: true }).waitFor({ state: 'visible' }); + check(await trustDialog.getByRole('button', { name: 'Keep blocking', exact: true }).evaluate(el => document.activeElement === el), 'host-key review focuses keep blocking'); + await geometry(target, width, height, 'host-key review'); await capture('host-key'); + await trustDialog.getByRole('button', { name: 'Trust new key', exact: true }).click(); await trustDialog.getByText('The key changed again.', { exact: false }).waitFor(); + check((await trustDialog.innerText()).includes(third.fingerprint), 'new fingerprint shown after a trust conflict'); + await trustDialog.getByRole('button', { name: 'Trust new key', exact: true }).click(); + await trustDialog.getByRole('button', { name: 'Review current host', exact: true }).waitFor(); + check(await trustDialog.locator('[data-cred-key="trust"]').count() === 0, 'stale host cannot be trusted'); + await page.route('**/credentials/scan', async route => { + const current = await store.public('staging-server'); + check(route.request().postDataJSON().revision === current.revision, 'review scans the current revision'); + return route.fulfill({ json: { ok: true, hostKey: { state: 'new', presented: { type: third.type, fingerprint: third.fingerprint } } } }); + }); + await trustDialog.getByRole('button', { name: 'Review current host', exact: true }).click(); + await trustDialog.getByRole('button', { name: 'Trust key', exact: true }).click(); await trustDialog.waitFor({ state: 'hidden' }); + await target.locator('.tc-cred-inspector').getByRole('button', { name: 'Close credential details' }).click(); + await edit('fixture-login'); editor = target.locator('.tc-cred-editor'); + await editor.getByRole('button', { name: 'Replace…', exact: true }).click(); await editor.locator('#cred-secret').fill(replacement); + const deleted = await store.public('fixture-login'); await store.remove({ id: deleted.id, revision: deleted.revision }); + await editor.locator('[data-cred-editor="save"]').click(); await editor.getByText('Deleted in another window', { exact: true }).waitFor(); + await editor.getByRole('button', { name: 'Save as new', exact: true }).click(); await editor.waitFor({ state: 'hidden' }); + check((await store.forUse('fixture-login')).secret === replacement, 'gone conflict can save as new with the typed key'); + const failRead = route => route.fulfill({ status: 500, json: { ok: false, code: 'store', error: 'Fixture read failed.' } }); + await page.route('**/credentials', failRead); await target.evaluate(() => window.dispatchEvent(new Event('focus'))); + await target.getByRole('alert').filter({ hasText: 'Fixture read failed.' }).waitFor(); + check(await target.locator('.tc-cred-row,.tc-cred-prow').count() === 0, 'read failure does not expose stale actionable rows'); await capture('read-error'); + await page.unroute('**/credentials', failRead); await target.getByRole('button', { name: 'Try again', exact: true }).click(); + await target.locator('[data-cred-action="inspect"][data-id="fixture-login"]').waitFor(); + await target.locator('[data-cred-action="inspect"][data-id="fixture-login"]').click(); + await target.locator('.tc-cred-inspector').getByRole('button', { name: 'Credential actions', exact: true }).click(); + await target.getByRole('menuitem', { name: 'Delete…', exact: true }).click(); + const deletion = target.getByRole('alertdialog'); await deletion.getByText('Backups of this volume still hold it', { exact: true }).waitFor(); await capture('delete'); + await deletion.getByRole('button', { name: 'Delete credential', exact: true }).click(); + await target.locator('[data-cred-action="inspect"][data-id="fixture-login"]').waitFor({ state: 'hidden' }); + await geometry(target, width, height, 'after delete'); + await target.waitForFunction(() => document.activeElement?.matches('#credential-list [data-cred-action="inspect"], #credential-list [data-cred-action="add"]')); + check(true, 'deletion restores focus to a remaining credential or Add'); + // Long metadata and a partial scan keep the list honest and usable. + const longId = 'long-' + 'a'.repeat(59); + const partialRead = async route => { + if (route.request().method() !== 'GET') return route.continue(); + const response = await route.fetch(), data = await response.json(); + data.usageWarnings = ['Fixture partial scan']; + data.credentials.push({ ...data.credentials.find(row => row.id === 'project-api'), id: longId, baseUrl: 'https://' + 'api.'.repeat(25) + 'example.com/' + 'long-path/'.repeat(18), test: null, usedIn: [{ name: 'a-very-long-skill-name-'.repeat(4), where: 'All agents', kind: 'skill' }, { name: 'AGENTS.md', kind: 'instructions' }] }); + return route.fulfill({ response, json: data }); }; - await add('build-server', 'Build server'); await add('staging-server', 'Staging server'); await add('project-api', 'Project API', 'api'); - await capture('saved'); - await target.getByRole('button', { name: 'Edit Project API', exact: true }).click(); - assert.equal(await target.getByLabel('Authentication', { exact: true }).inputValue(), 'header'); - await target.locator('#credential-secret').fill(token); - await target.getByLabel('Header name', { exact: true }).fill('Custom-Key'); - await target.getByLabel('Authentication', { exact: true }).selectOption('query'); - assert.equal(await target.getByLabel('Query parameter name', { exact: true }).inputValue(), 'api_key'); - assert.equal(await target.locator('#credential-secret').inputValue(), token); - await capture('query-auth'); - await target.getByLabel('Authentication', { exact: true }).selectOption('header'); - assert.equal(await target.locator('#credential-secret').inputValue(), token); - await target.getByLabel('Header name', { exact: true }).fill('Authorization'); - await target.getByLabel('Value prefix (optional)', { exact: true }).fill('Token'); - await capture('header-auth'); - await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); - await dialog.waitFor({ state: 'hidden' }); - await target.getByRole('button', { name: 'Reload', exact: true }).waitFor({ state: 'visible' }); - await target.getByRole('button', { name: 'Edit Project API', exact: true }).click(); - assert.equal(await target.getByLabel('Header name', { exact: true }).inputValue(), 'Authorization'); - assert.equal(await target.getByLabel('Value prefix (optional)', { exact: true }).inputValue(), 'Token'); - assert.equal(await target.locator('#credential-secret').inputValue(), ''); - await dialog.getByRole('button', { name: 'Cancel', exact: true }).click(); + await page.route('**/credentials', partialRead); await target.evaluate(() => window.dispatchEvent(new Event('focus'))); + await target.getByText('Some skills couldn’t be read. Usage may be incomplete.', { exact: true }).waitFor(); + await geometry(target, width, height, 'long metadata list'); + await target.evaluate(id => { location.hash = 'credentials/' + id; }, longId); + await target.locator('.tc-cred-inspector').getByRole('heading', { name: longId, exact: true }).waitFor(); + check((await target.locator('.tc-cred-inspector').innerText()).includes('At least 2 sources'), 'partial usage does not claim completeness'); + await geometry(target, width, height, 'long metadata inspector'); await capture('long-partial'); + await target.locator('.tc-cred-inspector').getByRole('button', { name: 'Close credential details' }).click(); + await page.unroute('**/credentials', partialRead); - assert.equal((await target.content()).includes(secret), false); - assert.equal((await target.content()).includes(token), false); - for (const [label, expected] of [['Build server', 't3-ssh build-server -- uptime'], ['Project API', 't3-api project-api GET account']]) { - await target.getByRole('button', { name: 'Copy skill command for ' + label, exact: true }).click(); - const copied = await target.evaluate(() => window.__copiedSkillCommand); - assert.equal(copied, expected); - assert.equal(copied.includes(secret), false); assert.equal(copied.includes(token), false); - } - await target.getByRole('button', { name: 'Edit Build server', exact: true }).click(); - assert.equal(await target.locator('#credential-secret').inputValue(), ''); - assert.equal(await target.getByLabel('Connection ID', { exact: true }).isDisabled(), true); - assert.equal(await target.getByLabel('Connection type').isDisabled(), true); - const box = await dialog.boundingBox(); - assert.ok(box.x >= -1 && box.y >= -1 && box.x + box.width <= width + 1 && box.y + box.height <= height + 1); - const buttons = await dialog.getByRole('button', { name: 'Save connection', exact: true }).boundingBox(); - assert.ok(buttons.y + buttons.height <= height, 'Save stays visible while fields scroll'); - await capture('edit'); - // An overlapping editor must not silently replace another window's edit. - const current = await (await f.request('/credentials')).json(); - const old = current.profiles.find(profile => profile.id === 'build-server'); - await f.request('/credentials/save', { profile: { ...old, label: 'Updated elsewhere' }, revision: current.revision }); - await target.locator('#credential-secret').fill('replacement-fixture-password'); - await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); - await target.getByRole('alert').waitFor(); - assert.equal(await target.locator('#credential-secret').inputValue(), 'replacement-fixture-password'); - assert.equal((await target.getByRole('alert').innerText()).includes('replacement-fixture-password'), false); - assert.equal(await target.locator('#credential-error').evaluate(el => document.activeElement === el), true); - await capture('conflict'); - await dialog.getByRole('button', { name: 'Cancel', exact: true }).click(); - await target.getByRole('button', { name: 'Reload', exact: true }).click(); - await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).waitFor(); - await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).click(); - await target.getByLabel('Name', { exact: true }).fill('Build server'); - // Saving twice while the request is pending still issues exactly one write. - let release, started, saves = 0; - const gate = new Promise(resolve => { release = resolve; }); - const arrived = new Promise(resolve => { started = resolve; }); - const intercept = async route => { saves++; started(); await gate; await route.continue(); }; - await page.route('**/credentials/save', intercept); - await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); - await Promise.race([arrived, new Promise((_, reject) => setTimeout(() => reject(new Error('Save request did not start: ' + theme + ' ' + width)), 5000).unref())]); - await target.locator('#credential-secret').press('Enter'); await page.keyboard.press('Escape'); - assert.equal(await dialog.count(), 1); assert.equal(await dialog.getByRole('button', { name: 'Cancel', exact: true }).isDisabled(), true); - release(); await dialog.waitFor({ state: 'hidden' }); await page.unroute('**/credentials/save', intercept); - assert.equal(saves, 1); await target.getByRole('button', { name: 'Edit Build server', exact: true }).waitFor(); - await page.route('**/credentials/test', route => route.fulfill({ json: { ok: true, message: 'Connection succeeded.' } })); - await target.getByRole('button', { name: 'Test Project API', exact: true }).click(); - await target.getByText('Connection succeeded', { exact: true }).waitFor(); - const failRead = route => route.fulfill({ status: 500, json: { ok: false, error: 'Fixture read failed.' } }); - await page.route('**/credentials', failRead); - await target.getByRole('button', { name: 'Reload', exact: true }).click(); await target.getByRole('alert').waitFor(); - assert.equal(await target.getByRole('button', { name: 'Edit Build server', exact: true }).isDisabled(), true); - await capture('read-error'); await page.unroute('**/credentials', failRead); - await target.getByRole('button', { name: 'Reload', exact: true }).click(); - await target.getByRole('button', { name: 'Delete Staging server', exact: true }).click(); - await target.getByRole('alertdialog').getByRole('button', { name: 'Delete connection', exact: true }).click(); - await target.locator('[data-key="credential-staging-server"]').waitFor({ state: 'hidden' }); - assert.equal(await target.evaluate(() => document.documentElement.scrollWidth > innerWidth), false); - for (const response of await Promise.all(responses)) for (const value of [secret, token, 'replacement-fixture-password']) assert.equal(response.includes(value), false); - assert.deepEqual(errors, []); await capture('after-delete'); - console.log(`PASS server credentials: ${theme} ${width}x${height}${embedded ? ' embedded' : ''}`); - await page.close(); + check(!(await target.content()).includes(secret) && !(await target.content()).includes(token) && !(await target.content()).includes(replacement), 'no saved or typed secrets remain in markup'); + for (const body of await Promise.all(responseBodies)) for (const value of [secret, token, replacement]) check(!body.includes(value), 'no credential response echoes a secret'); + assert.deepEqual(pageErrors, []); checks++; await page.close(); + console.log(`PASS credentials ${theme} ${width} ${mode} (${checks} checks so far)`); } - assert.equal(f.logs().includes(secret), false); assert.equal(f.logs().includes(token), false); -} finally { await browser.close(); await f.close(); } + check(!f.logs().includes(secret) && !f.logs().includes(token), 'service logs do not expose fixture credentials'); + console.log('PASS ' + checks + ' Credentials browser checks'); +} finally { await browser.close(); loopback.closeAllConnections(); await new Promise(resolve => loopback.close(resolve)); await f.close(); } diff --git a/scripts/credentials-visual-audit.mjs b/scripts/credentials-visual-audit.mjs new file mode 100644 index 00000000..2b9ec059 --- /dev/null +++ b/scripts/credentials-visual-audit.mjs @@ -0,0 +1,72 @@ +#!/usr/bin/env node +// Captures the real console with explicitly synthetic in-memory fixture data. +// Run console-preview.mjs first. Never point this at a production Setup URL. +import assert from 'node:assert/strict'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); +let chromium; try { ({ chromium } = require('playwright')); } catch { ({ chromium } = require('playwright-core')); } +const { framed } = require('./lib/console-fixtures.cjs'); +const base = process.argv[2] || 'http://127.0.0.1:23966/__setup/'; +assert.ok(['127.0.0.1', 'localhost'].includes(new URL(base).hostname), 'Visual fixtures must run on loopback.'); +const output = process.env.T3_CREDENTIALS_VISUAL_OUTPUT || '/tmp/t3-credentials-visual'; await fs.mkdir(output, { recursive: true }); +const fixture = await (await fetch(new URL('credentials', base))).json(); +assert.equal(fixture.credentials.length, 5, 'Use the five-row console fixture.'); +const browser = await chromium.launch({ executablePath: process.env.CHROME_PATH || '/usr/bin/chromium', args: ['--no-sandbox'] }); +const themes = (process.env.T3_CREDENTIALS_VISUAL_THEMES || 'light,dark').split(','); +const cases = ['list', 'empty', 'inspect-ssh', 'inspect-api', 'add-ssh', 'add-api', 'conflict', 'host-key', 'delete']; +let captures = 0; +try { + for (const theme of themes) for (const mode of ['tab', 'phone']) for (const state of mode === 'phone' ? ['list', 'inspect-api', 'add-ssh'] : cases) { + if (process.env.T3_CREDENTIALS_VISUAL_STATES && !process.env.T3_CREDENTIALS_VISUAL_STATES.split(',').includes(state)) continue; + const width = mode === 'tab' ? 1040 : 390, height = mode === 'tab' ? 820 : 844; + const page = await browser.newPage({ viewport: { width, height }, deviceScaleFactor: mode === 'phone' ? 2 : 1, reducedMotion: 'reduce', colorScheme: theme }); + const errors = []; page.on('pageerror', error => errors.push(error.message)); + await page.addInitScript(value => localStorage.setItem('t3-console-theme', value), theme); + await page.addInitScript(value => { const NativeDate = Date; window.Date = class extends NativeDate { constructor(...args) { super(...(args.length ? args : [value])); } static now() { return value; } }; }, Date.parse(fixture.credentials.find(row => row.id === 'build-server').test.at) + 120000); + await page.route('**/credentials', async route => { + if (route.request().method() !== 'GET') return route.continue(); + const credentials = state === 'empty' ? [] : fixture.credentials.filter(row => !(state === 'add-ssh' && row.id === 'build-server') && !(state === 'add-api' && row.id === 'project-api')); + return route.fulfill({ json: { ...fixture, credentials } }); + }); + const url = new URL(base); url.search = 'embed=t3&host=tab&layout=' + (mode === 'phone' ? 'compact' : 'wide') + '&theme=' + theme; url.hash = 'credentials'; + const target = await framed(page, url.href); + await target.locator('#page-credentials:not([hidden]) .tc-page-title').waitFor(); + await target.getByText(state === 'empty' ? 'Keep secrets out of chats and skills' : 'Search credentials', { exact: true }).count(); + if (state === 'empty') await target.getByRole('button', { name: 'Add credential…', exact: true }).waitFor(); + else await target.locator('[data-cred-action="inspect"]').first().waitFor(); + await target.locator('#page-credentials .tc-page-title').click(); + if (state.startsWith('inspect') || state === 'host-key' || state === 'delete' || state === 'conflict') { + const id = state === 'inspect-ssh' || state === 'conflict' ? 'build-server' : state === 'host-key' ? 'staging-server' : mode === 'phone' ? 'home-assistant' : 'project-api'; + await target.locator('[data-cred-action="inspect"][data-id="' + id + '"]').click(); await target.locator('.tc-cred-inspector').waitFor(); + } + if (state === 'host-key') { await target.locator('.tc-cred-inspector [data-cred-inspect="review"]').click(); await target.locator('.tc-cred-dialog [data-cred-key="trust"]:enabled').waitFor(); } + if (state === 'delete') { await target.locator('.tc-cred-inspector [data-cred-inspect="menu"]').click(); await target.getByRole('menuitem', { name: 'Delete…', exact: true }).click(); await target.getByRole('alertdialog').waitFor(); } + if (state.startsWith('add')) { + await target.getByRole('button', { name: 'Add credential', exact: true }).click(); const editor = target.locator('.tc-cred-editor'); + await editor.getByLabel('Name', { exact: true }).fill(state === 'add-ssh' ? 'build-server' : 'project-api'); + if (state === 'add-api') { + await editor.getByRole('button', { name: 'HTTP API', exact: true }).click(); await editor.getByLabel('Base URL', { exact: true }).fill('https://api.example.com/v1/'); + await editor.getByRole('button', { name: 'Header', exact: true }).click(); await editor.getByLabel('Header name', { exact: true }).fill('X-API-Key'); await editor.getByLabel('GET test path (optional)', { exact: true }).fill('account'); + } else { await editor.getByLabel('Host', { exact: true }).fill('192.0.2.10'); await editor.getByLabel('Username', { exact: true }).fill('deploy'); } + await editor.locator('#cred-secret').fill('synthetic-visual-fixture'); + await editor.locator('[data-cred-editor="test"]').click(); + if (state === 'add-ssh') { await editor.getByLabel('Trust this host key', { exact: true }).check(); await editor.getByText('Signed in as deploy', { exact: true }).waitFor(); } + else await editor.getByText('Connected · HTTP 200', { exact: true }).waitFor(); + } + if (state === 'conflict') { + await target.locator('.tc-cred-inspector [data-cred-inspect="edit"]').click(); const editor = target.locator('.tc-cred-editor'); + await editor.getByRole('button', { name: 'Replace…', exact: true }).click(); await editor.locator('#cred-secret').fill('synthetic-replacement'); + const original = fixture.credentials.find(row => row.id === 'build-server'); + await page.route('**/credentials/save', route => route.fulfill({ status: 409, json: { ok: false, code: 'changed', error: 'Changed elsewhere.', current: { ...original, host: '192.0.2.11', updatedAt: new Date().toISOString(), secretChangedAt: new Date().toISOString(), revision: '0123456789abcdef' } } })); + await editor.locator('[data-cred-editor="save"]').click(); await editor.locator('#cred-conflict').waitFor(); + } + await target.evaluate(async () => { await document.fonts.ready; await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); }); + const geometry = await target.evaluate(() => ({ overflow: document.documentElement.scrollWidth > innerWidth + 1, panels: [...document.querySelectorAll('.tc-cred-editor,.tc-cred-dialog,.tc-cred-inspector')].map(el => { const r = el.getBoundingClientRect(); return { x: r.x, y: r.y, right: r.right, bottom: r.bottom }; }) })); + assert.equal(geometry.overflow, false); for (const r of geometry.panels) assert.ok(r.x >= -1 && r.y >= -1 && r.right <= width + 1 && r.bottom <= height + 1, JSON.stringify(r)); + await page.locator('iframe').screenshot({ path: path.join(output, `${theme}-${mode}-${state}.png`) }); captures++; + assert.deepEqual(errors, []); await page.close(); console.log('PASS visual ' + theme + ' ' + mode + ' ' + state); + } + console.log('PASS ' + captures + ' aligned Credentials visual captures'); +} finally { await browser.close(); } diff --git a/scripts/fixtures/console/credentials.json b/scripts/fixtures/console/credentials.json index dc3b185b..60a8303c 100644 --- a/scripts/fixtures/console/credentials.json +++ b/scripts/fixtures/console/credentials.json @@ -1,9 +1,163 @@ { "ok": true, - "revision": "fixture-credentials", - "profiles": [ - { "id": "build-server", "label": "Build server", "type": "ssh", "host": "192.0.2.10", "username": "deploy", "port": 22, "hasSecret": true }, - { "id": "staging-server", "label": "Staging server", "type": "ssh", "host": "192.0.2.20", "username": "root", "port": 22, "hasSecret": true }, - { "id": "project-api", "label": "Project API", "type": "api", "baseUrl": "https://api.example.com/v1/", "authType": "header", "authName": "X-API-Key", "authPrefix": "", "testPath": "account", "hasSecret": true } + "usageAt": "2026-10-30T22:00:05Z", + "usageWarnings": [], + "credentials": [ + { + "id": "build-server", + "type": "ssh", + "host": "192.0.2.10", + "username": "deploy", + "port": 22, + "hasSecret": true, + "createdAt": "2026-10-26T18:04:11Z", + "updatedAt": "2026-10-26T18:04:11Z", + "secretChangedAt": "2026-10-26T18:04:11Z", + "revision": "9c1f0e7a3b5d4c21", + "test": { + "at": "2026-10-30T21:58:00Z", + "ok": true, + "code": "ok", + "ms": 1180, + "detail": { + "user": "deploy" + } + }, + "hostKey": { + "type": "ssh-ed25519", + "fingerprint": "SHA256:p2QkL0n8sT4vYc1bZr7eWq9uKx3mHf6dJg2aNo5Xf7cA", + "trustedAt": "2026-10-26T18:04:30Z", + "carried": false + }, + "usedIn": [ + { + "kind": "skill", + "name": "deploy", + "where": "Claude Code, Codex" + }, + { + "kind": "skill", + "name": "server-health", + "where": "All agents" + } + ] + }, + { + "id": "home-assistant", + "type": "api", + "baseUrl": "https://ha.example.net/api/", + "authType": "bearer", + "testPath": "", + "hasSecret": true, + "createdAt": "2026-10-20T20:02:55Z", + "updatedAt": "2026-10-20T20:02:55Z", + "secretChangedAt": "2026-10-20T20:02:55Z", + "revision": "7b3c19e05d2a4f61", + "test": { + "at": "2026-10-29T18:40:03Z", + "ok": false, + "code": "rejected", + "ms": 312, + "detail": { + "status": 401 + } + }, + "hostKey": null, + "usedIn": [ + { + "kind": "skill", + "name": "lights", + "where": "All agents" + } + ] + }, + { + "hasSecret": true, + "createdAt": "2026-10-26T18:04:11Z", + "updatedAt": "2026-10-26T18:04:11Z", + "secretChangedAt": "2026-10-26T18:04:11Z", + "revision": "e6a4c2b0f8d6e4c2", + "test": { + "at": "2026-10-30T21:00:00Z", + "ok": true, + "code": "ok", + "ms": 184, + "detail": { + "status": 200 + } + }, + "hostKey": null, + "usedIn": [ + { + "kind": "skill", + "name": "project-sync", + "where": "Claude Code" + } + ], + "id": "project-api", + "type": "api", + "baseUrl": "https://api.example.com/v1/", + "authType": "header", + "authName": "X-API-Key", + "authPrefix": "", + "testPath": "account" + }, + { + "hasSecret": true, + "createdAt": "2026-10-26T18:04:11Z", + "updatedAt": "2026-10-26T18:04:11Z", + "secretChangedAt": "2026-10-26T18:04:11Z", + "revision": "e6a4c2b0f8d6e4c2", + "test": { + "at": "2026-10-30T21:45:00Z", + "ok": false, + "code": "host-key-changed", + "ms": 350, + "detail": { + "trusted": { + "type": "ssh-ed25519", + "fingerprint": "SHA256:p2QkL0n8sT4vYc1bZr7eWq9uKx3mHf6dJg2aNo5Xf7cA" + }, + "presented": { + "type": "ssh-ed25519", + "fingerprint": "SHA256:d1HvN3Qx0rZ8fBc5kW9sTa6mL7uE4oG2jYvIhPnScUs" + } + } + }, + "hostKey": { + "type": "ssh-ed25519", + "fingerprint": "SHA256:p2QkL0n8sT4vYc1bZr7eWq9uKx3mHf6dJg2aNo5Xf7cA", + "trustedAt": "2026-10-26T18:04:11Z", + "carried": false + }, + "usedIn": [ + { + "kind": "skill", + "name": "deploy", + "where": "Claude Code" + } + ], + "id": "staging-server", + "type": "ssh", + "host": "192.0.2.20", + "port": 2222, + "username": "root" + }, + { + "hasSecret": true, + "createdAt": "2026-10-26T18:04:11Z", + "updatedAt": "2026-10-26T18:04:11Z", + "secretChangedAt": "2026-10-26T18:04:11Z", + "revision": "e6a4c2b0f8d6e4c2", + "test": null, + "hostKey": null, + "usedIn": [], + "id": "weather", + "type": "api", + "baseUrl": "https://api.weather.example/v3/", + "authType": "query", + "authName": "apikey", + "testPath": "" + } ] } diff --git a/scripts/lib/credentials-fixtures.cjs b/scripts/lib/credentials-fixtures.cjs new file mode 100644 index 00000000..8d9ab06a --- /dev/null +++ b/scripts/lib/credentials-fixtures.cjs @@ -0,0 +1,62 @@ +// Synthetic, in-memory credentials. No connection or secret leaves this fixture. +const { randomBytes } = require('node:crypto'); +const { fixture, shiftTimes } = require('./console-fixtures.cjs'); +const clone = value => JSON.parse(JSON.stringify(value)); +const revision = () => randomBytes(8).toString('hex'); +function createCredentialsFixtures() { + const data = shiftTimes(fixture('credentials.json'), Date.now() - Date.parse('2026-10-30T22:00:00Z')); + const key = { type: 'ssh-ed25519', fingerprint: data.credentials.find(row => row.id === 'build-server').hostKey.fingerprint }; + const now = () => new Date().toISOString(); + const find = id => data.credentials.find(row => row.id === id); + const status = () => ({ count: data.credentials.length, attention: data.credentials.filter(row => row.type === 'ssh' && !row.hostKey || row.test?.ok === false).map(row => ({ id: row.id, code: row.type === 'ssh' && !row.hostKey ? 'host-key-untrusted' : row.test.code })) }); + const body = value => ({ body: { ok: true, ...clone(value) } }); + const fail = (code, error, extra = {}) => ({ status: 409, body: { ok: false, code, error, ...clone(extra) } }); + const scan = profile => { + const presented = profile.id === 'staging-server' && profile.test?.code === 'host-key-changed' ? profile.test.detail.presented : key; + return { state: !profile.hostKey ? 'new' : profile.hostKey.fingerprint === presented.fingerprint ? 'trusted' : 'changed', presented, ...(profile.hostKey ? { trusted: { type: profile.hostKey.type, fingerprint: profile.hostKey.fingerprint } } : {}) }; + }; + const respond = async (method, url, input = {}) => { + const route = url.pathname.replace(/^\/__setup/, ''); + if (!/^\/credentials(?:\/|$)/.test(route)) return null; + if (method === 'GET' && route === '/credentials') return body({ ...data, usageAt: now() }); + const profile = find(input.id || input.credential?.id); + if (route.endsWith('/create') || route.endsWith('/save')) { + if (route.endsWith('/create') && profile) return fail('taken', 'That name is already taken.'); + if (route.endsWith('/save') && !profile) return fail('gone', 'This credential was deleted elsewhere.'); + if (profile && input.revision !== profile.revision) return fail('changed', 'This credential changed elsewhere.', { current: profile }); + const { secret: _secret, ...visible } = input.credential; + const next = { ...profile, ...visible, revision: revision(), hasSecret: true, createdAt: profile?.createdAt || now(), updatedAt: now(), secretChangedAt: input.credential.secret ? now() : profile?.secretChangedAt || now(), test: null, usedIn: profile?.usedIn || [], hostKey: profile?.host === visible.host && profile?.port === visible.port ? profile.hostKey : null }; + if (input.trust?.fingerprint === key.fingerprint) next.hostKey = { ...key, trustedAt: now(), carried: false }; + data.credentials = [...data.credentials.filter(row => row.id !== next.id), next]; return body({ credential: next }); + } + if ((route.endsWith('/scan') || route.endsWith('/trust')) && input.id) { + if (!profile) return fail('gone', 'This credential is no longer saved.'); + if (input.revision !== undefined && input.revision !== profile.revision) return fail('changed', 'This credential changed elsewhere.', { current: profile }); + } + if (route.endsWith('/scan')) return body({ hostKey: scan(profile || input) }); + if (route.endsWith('/test')) { + const target = input.draft ? { ...profile, ...input.draft } : profile; + if (!target) return fail('gone', 'This credential is no longer saved.'); + const hostKey = target.type === 'ssh' ? scan(target) : null; + const result = hostKey && hostKey.state !== 'trusted' && input.trust?.fingerprint !== hostKey.presented.fingerprint + ? { ok: false, code: hostKey.state === 'changed' ? 'host-key-changed' : 'host-key-untrusted', detail: hostKey.trusted ? { trusted: hostKey.trusted, presented: hostKey.presented } : {}, hostKey } + : target.id === 'home-assistant' ? { ok: false, code: 'rejected', detail: { status: 401 } } : { ok: true, code: 'ok', detail: target.type === 'ssh' ? { user: target.username } : { status: 200 } }; + Object.assign(result, { ms: 184, at: now() }); if (!input.draft) profile.test = result; + return body({ result }); + } + if (!profile) return fail('gone', 'This credential is no longer saved.'); + if (route.endsWith('/trust')) { + const scanned = scan(profile); + if (input.fingerprint !== scanned.presented.fingerprint) return fail('key-changed', 'The server presented a different key.', { presented: scanned.presented }); + profile.hostKey = { ...scanned.presented, trustedAt: now(), carried: false }; profile.test = null; return body({ hostKey: profile.hostKey }); + } + if (route.endsWith('/forget-host-key')) { profile.hostKey = null; profile.test = null; return body({}); } + if (route.endsWith('/remove')) { + if (input.revision !== profile.revision) return fail('changed', 'This credential changed elsewhere.', { current: profile }); + data.credentials = data.credentials.filter(row => row !== profile); return body({}); + } + return { status: 404, body: { ok: false, error: 'Unknown fixture credential action.' } }; + }; + return { respond, status }; +} +module.exports = { createCredentialsFixtures }; diff --git a/scripts/setup-tab-audit.js b/scripts/setup-tab-audit.js index 987d886d..78075f68 100644 --- a/scripts/setup-tab-audit.js +++ b/scripts/setup-tab-audit.js @@ -5,7 +5,7 @@ const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const { chromium } = require('playwright'); -const { framed, routeConsole, visit, statusFor, portsFor } = require('./lib/console-fixtures.cjs'); +const { framed, routeConsole, visit, statusFor, portsFor, routesTable } = require('./lib/console-fixtures.cjs'); const BASE = process.argv[2] || 'http://127.0.0.1:23920/__setup/'; const OUT = process.env.T3_TAB_UI_OUTPUT; (async () => { @@ -27,7 +27,7 @@ const OUT = process.env.T3_TAB_UI_OUTPUT; assert.equal(await menu.getAttribute('role'),'menu'); assert.equal(await menu.locator('[aria-current=page]').textContent().then(t=>t.trim().startsWith('Agents')),true); assert.equal(await menu.locator('[data-menu-cancel]').count(),0); - assert.equal(await menu.locator('[role=menuitemradio]').count(),12); + assert.equal(await menu.locator('[role=menuitemradio]').count(),routesTable().PAGES.length); assert.equal(await menu.locator('[aria-current=page] > svg').count(),2); const box=await menu.boundingBox();assert(box.x>=0&&box.x+box.width<=width+1&&box.y>=0&&box.y+box.height<=900); const row=await menu.locator('[role=menuitemradio]').first().boundingBox();assert.equal(row.height,width<640?44:32); diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 80903917..43e2704d 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -831,6 +831,22 @@ mcp_editor_works() { } check "MCP controls refresh immediately and preserve editor revisions and values" mcp_editor_works +credentials_browser_works() { + [ "$HAS_BROWSER" -eq 1 ] || return 0 + local audit=/tmp/t3-credentials-audit + docker exec "$NAME" mkdir -p "$audit/scripts/lib" "$audit/scripts/fixtures" "$audit/tests/fixtures" "$audit/docker" || return 1 + docker exec "$NAME" ln -sfn /opt/t3-setup "$audit/docker/setup" || return 1 + docker cp scripts/credentials-ui-audit.mjs "$NAME:$audit/scripts/credentials-ui-audit.mjs" >/dev/null 2>&1 || return 1 + docker cp scripts/lib/console-fixtures.cjs "$NAME:$audit/scripts/lib/console-fixtures.cjs" >/dev/null 2>&1 || return 1 + docker cp scripts/fixtures/console "$NAME:$audit/scripts/fixtures/console" >/dev/null 2>&1 || return 1 + for helper in credentials.mjs credential-keys.mjs; do + docker cp "tests/fixtures/$helper" "$NAME:$audit/tests/fixtures/$helper" >/dev/null 2>&1 || return 1 + done + docker exec -e CHROME_PATH=/usr/bin/chromium -e NODE_PATH=/opt/t3-mcp/lib/node_modules/@playwright/mcp/node_modules -e T3_CREDENTIALS_UI_WIDTHS=390,640,1280 \ + "$NAME" node "$audit/scripts/credentials-ui-audit.mjs" >>"$UI_AUDIT_LOG" 2>&1 +} +check "Credentials drafts, host trust, conflicts and recovery work on desktop, phone and Settings" credentials_browser_works + files_browser_works() { [ "$HAS_BROWSER" -eq 1 ] || return 0 docker exec "$NAME" mkdir -p /tmp/t3-files-audit/lib /tmp/t3-files-audit/fixtures || return 1 diff --git a/tests/credential-model.test.mjs b/tests/credential-model.test.mjs new file mode 100644 index 00000000..274b6ae6 --- /dev/null +++ b/tests/credential-model.test.mjs @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import vm from 'node:vm'; +import { readFileSync } from 'node:fs'; +const ctx = vm.createContext({ URL }); +for (const file of ['routes', 'model', 'mcp-command', 'credential-model']) vm.runInContext(readFileSync(new URL('../docker/setup/client/' + file + '.js', import.meta.url), 'utf8'), ctx); +const S = vm.runInContext('T3CredentialModel', ctx), plain = value => JSON.parse(JSON.stringify(value)); +const api = { id: 'project-api', type: 'api', baseUrl: 'https://api.example.test/v1', authType: 'header', authName: 'X-Key', authPrefix: 'Token', testPath: 'account' }; +test('drafts only copy public editable fields and previews always mask the authentication value', () => { + const draft = S.draftOf({ ...api, secret: 'never-copy-me', test: { detail: { secret: 'never-copy-me' } }, revision: 'never-copy-me' }); + assert.equal(JSON.stringify(draft).includes('never-copy-me'), false); + assert.equal(S.request(draft, true), 'GET /v1/account\nHost: api.example.test\nX-Key: Token ••••••••\naccept: application/json'); + assert.match(S.request({ ...draft, authType: 'query', authName: 'api key' }), /api\+key=••••••••/); + assert.equal(S.commands(draft)[0], 't3-api project-api GET account'); + assert.match(S.snippet(draft), /Don’t read or print credential files/); +}); +test('draft validation mirrors saved path and authentication restrictions with field errors', () => { + const valid = { ...S.draftOf(api), baseUrl: api.baseUrl }; + assert.deepEqual(plain(S.validate(valid, { secret: 'fixture' })), {}); + for (const [field, value] of [['id', 'Bad ID'], ['baseUrl', 'https://user:pass@example.com/v1/'], ['authName', 'Host'], ['authPrefix', 'Token\r\n'], ['testPath', '../escape'], ['testPath', '%2e%2e/escape']]) { + assert.ok(S.validate({ ...valid, [field]: value }, { secret: 'fixture' })[field], field); + } + assert.match(S.validate(valid, { secret: 'fixture', names: ['project-api'] }).id, /taken/); + assert.equal(S.validate(valid, { hasSecret: true, editing: true }).secret, undefined); + assert.ok(S.validate(valid).secret); +}); +test('result precedence, attention filtering and metadata searches agree with the server', () => { + const profile = { ...api, hasSecret: true, test: { ok: false, code: 'timeout' } }; + assert.equal(Boolean(S.needsAttention(profile, [])), false); + assert.equal(Boolean(S.needsAttention(profile, [{ id: profile.id }])), true); + assert.equal(S.state({ id: 'server', type: 'ssh', hostKey: null, test: { code: 'ok' } }).code, 'host-key-untrusted'); + assert.equal(S.state(profile).action, 'Test'); + assert.equal(S.matches(profile, 'x-key'), true); assert.equal(S.matches(profile, 'api.example'), true); assert.equal(S.matches(profile, 'secret'), false); + assert.deepEqual(plain(S.changes(api, { ...api, authName: 'X-Other', secretChangedAt: 'changed' })), ['authName']); +}); diff --git a/tests/credentials-service.test.mjs b/tests/credentials-service.test.mjs index c6c1fb1a..c7b3ac05 100644 --- a/tests/credentials-service.test.mjs +++ b/tests/credentials-service.test.mjs @@ -150,3 +150,12 @@ for (const [clientLine, remoteLine, status, code] of [ } }); assert.equal(result.code, code); assert.equal(JSON.stringify(result).includes(ssh.secret), false); }); + +test('a review opened before an address change cannot show or trust keys for a new target', async t => { + const f = await fixture(t), original = (await f.create(ssh)).credential; + await f.store.save({ credential: { ...ssh, host: 'other-host' }, revision: original.revision }); + for (const route of ['/credentials/scan', '/credentials/trust']) { + await assert.rejects(f.service.handle(route, { id: original.id, revision: original.revision, fingerprint: f.key.fingerprint }), { status: 409, code: 'changed' }); + } + assert.equal(f.scans, 0); assert.equal(f.signins, 0); assert.equal((await f.store.public(ssh.id)).hostKey, null); +}); diff --git a/tests/credentials-store.test.mjs b/tests/credentials-store.test.mjs index 9627a137..066db681 100644 --- a/tests/credentials-store.test.mjs +++ b/tests/credentials-store.test.mjs @@ -160,3 +160,10 @@ test('state recovery replaces its directory entry without following a symlink', assert.equal((await fs.lstat(file)).isSymbolicLink(), false); assert.equal(JSON.stringify(await store.list()).includes(api.secret), false); }); + +test('replacement timestamps advance even when two writes share a clock tick', async t => { + const { store, create } = await fixture(t, { store: { clock: () => Date.parse('2026-10-30T10:00:00Z') } }); + const a = (await create(api)).credential; + const b = (await store.save({ credential: { ...api, secret: 'a-different-synthetic-token' }, revision: a.revision })).credential; + assert.notEqual(a.secretChangedAt, b.secretChangedAt); assert.ok(Date.parse(b.updatedAt) > Date.parse(a.updatedAt)); +}); diff --git a/tests/fixtures/standalone-shell.html b/tests/fixtures/standalone-shell.html index a24aebf8..bb2eb73a 100644 --- a/tests/fixtures/standalone-shell.html +++ b/tests/fixtures/standalone-shell.html @@ -15,7 +15,7 @@

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 yOk!YAW9-I7 literal 0 HcmV?d00001 diff --git a/docs/server-credentials.md b/docs/server-credentials.md new file mode 100644 index 00000000..d8187e34 --- /dev/null +++ b/docs/server-credentials.md @@ -0,0 +1,95 @@ +# Server credentials + +**Setup → Server credentials** keeps SSH passwords and API bearer tokens out +of skill files and agent prompts. Save a connection, then give the agent its +connection ID. The page supports adding, editing, testing and deleting connections +on desktop and phone, including inside T3 Code's Settings → Setup dialog. + +![Server credentials in the setup console, using example addresses.](media/server-credentials/desktop.png) + +Choose **Add connection**, enter a name and a stable ID such as `homeserver`, +then choose a type: + +- **SSH password:** hostname or IP, username, port and password. +- **API bearer token:** the full API base URL and token. For Home Assistant, + include `/api/`, for example `http://homeassistant.local/api/`. + +Saved passwords and tokens are never returned to the browser. **Edit** changes +connection details and can replace the secret; leave the secret blank to keep +its existing value. A stale editor cannot overwrite changes from another +window: close it, reload the list, and reopen the connection before saving again. +Connection IDs and types stay fixed; create another entry to change them. + +**Test** uses the saved login: SSH runs `true`, and API sends a GET to the saved +base URL. It returns only success or a short error, without the response body. +An API whose base URL does not accept GET may fail this test even when its token +works for other endpoints. SSH remembers a new host key on first use and refuses +a changed key. Verify first-use host identity on a trusted network. + +## Use from an agent or terminal + +These commands are installed in both image variants: + +```sh +t3-ssh homeserver -- uptime +t3-ssh homeassistant-ssh -- 'ha core info' +t3-api homeassistant GET states/light.kitchen +printf '%s' '{"entity_id":"light.kitchen"}' | + t3-api homeassistant POST services/light/turn_on --stdin +``` + +`t3-ssh` runs a non-interactive remote command. Supply a complete remote shell +command as one quoted argument when it includes pipelines or shell syntax. Its +stdin remains available for scripts, for example `t3-ssh homeserver -- bash -s`. +It uses password or keyboard-interactive authentication; multi-step challenges +and interactive terminal sessions are outside this helper's scope. + +`t3-api` accepts GET, HEAD, POST, PUT, PATCH and DELETE. Paths are relative to the +saved base URL, without a leading slash. The optional `--stdin` supplies a JSON +body of at most 1 MiB. Requests stay under that base URL; redirects are refused +so a token cannot be forwarded to another destination. Responses go to stdout; +HTTP failures return a nonzero exit status. This helper covers REST calls, not +Home Assistant's websocket API. + +Both helpers read their credentials internally, without including their values +in command arguments. Matching literal, JSON-escaped, URL-encoded and Base64 +values are filtered from response output. This avoids accidental echoes of the +stored credential; it cannot recognize every possible transformation or prevent +an agent deliberately reading files with its shell. + +## Move credentials out of skills + +Create these three entries through the page: + +| Connection ID | Type | Purpose | +| --- | --- | --- | +| `homeserver` | SSH password | HomeServer commands | +| `homeassistant-ssh` | SSH password | Home Assistant SSH commands | +| `homeassistant` | API bearer token | Home Assistant REST API | + +Test each entry, then replace passwords and tokens in your skills with helper +commands. Example replacement skills are in +[`examples/skills`](../examples/skills). Keep any server-specific instructions +you still need. Install the image containing these helpers before switching +existing skills. Rotate credentials that previously appeared in chat or skill +history; deleting the text does not remove earlier copies. + +## Storage and access + +Connections are stored as plaintext JSON in +`$T3CODE_HOME/server-credentials/credentials.json` (normally +`/home/t3/.t3/server-credentials/credentials.json`). The directory is owner-only +(0700) and the file is owner-only (0600). The default `/home/t3` volume keeps +them across restarts, image upgrades and recreations. A deployment that mounts +only `T3CODE_HOME` keeps them there too. Protect backups of this volume. + +The feature keeps credentials out of ordinary prompts and helper output. It is +not an encrypted vault or a permission boundary against an agent with shell +access. The authenticated console and helpers run as the same container user; +any process with that user's file access can read the saved values. SSH passes +the password to its askpass child through its private child environment. +Never request a credential dump in a chat or print that environment. + +The page uses the existing setup authentication and request protections, and +requires HTTPS or a trusted private connection like the rest of the setup console. +It does not put secrets in `/status`, downloadable skills or browser storage. diff --git a/examples/skills/ssh-ha/SKILL.md b/examples/skills/ssh-ha/SKILL.md new file mode 100644 index 00000000..7c869156 --- /dev/null +++ b/examples/skills/ssh-ha/SKILL.md @@ -0,0 +1,19 @@ +--- +name: ssh-ha +description: Use Home Assistant SSH or its REST API when explicitly asked to work on Home Assistant. +--- + +Use the saved connections; no password or API token belongs in this skill. + +```sh +t3-ssh homeassistant-ssh -- 'ha core info' +t3-api homeassistant GET states/light.kitchen +printf '%s' '{"entity_id":"light.kitchen"}' | + t3-api homeassistant POST services/light/turn_on --stdin +``` + +`homeassistant-ssh` is the SSH login. `homeassistant` is the API bearer token +and base URL, including `/api/`. The port is part of that saved URL. +Manage both in Setup → Server credentials. Do not read or print credential files +or the helper's child environment. The API helper handles REST requests; it does +not handle Home Assistant's websocket automation traces. diff --git a/examples/skills/ssh/SKILL.md b/examples/skills/ssh/SKILL.md new file mode 100644 index 00000000..680984c5 --- /dev/null +++ b/examples/skills/ssh/SKILL.md @@ -0,0 +1,14 @@ +--- +name: ssh +description: SSH to HomeServer when explicitly asked to use that server. +--- + +Use the saved `homeserver` SSH connection: + +```sh +t3-ssh homeserver -- '' +``` + +Connection details and the password are managed in Setup → Server credentials. +If the connection is missing or authentication fails, ask the user to check that +page. Do not read or print credential files or the helper's child environment. diff --git a/scripts/console-preview.mjs b/scripts/console-preview.mjs index f3608c32..4207f3a7 100644 --- a/scripts/console-preview.mjs +++ b/scripts/console-preview.mjs @@ -33,6 +33,7 @@ http.createServer(async (req, res) => { const result = await files.respond(req.method, url, input) || await mcp.respond(req.method, url, input) || storage.respond(req.method, url, input) || api.respond(req.method, url, input) || (url.pathname.endsWith('/status') ? { body: { ...statusFor('skills'), storage: storage.status(), context: { ...statusFor('skills').context, mcp: mcp.status() } } } : url.pathname.endsWith('/ports') ? { body: portsFor('ready') } : url.pathname.endsWith('/providers') ? { body: fixture('providers.json') } + : url.pathname.endsWith('/credentials') && req.method === 'GET' ? { body: fixture('credentials.json') } : { status: 404, body: { ok: false, error: 'This is a read-only fixture preview. No live API is connected.' } }); if (result.body?.etag && req.headers['if-none-match'] === result.body.etag) { res.writeHead(304, { ETag: result.body.etag }); res.end(); return; } res.writeHead(result.status || 200, { 'content-type': 'application/json', 'cache-control': 'no-store', ...result.headers }); diff --git a/scripts/credentials-smoke.mjs b/scripts/credentials-smoke.mjs new file mode 100644 index 00000000..b61beeba --- /dev/null +++ b/scripts/credentials-smoke.mjs @@ -0,0 +1,39 @@ +#!/usr/bin/env node +// Runs inside either built image, using a disposable connection and local API. +import assert from 'node:assert/strict'; +import { createServer } from 'node:http'; +import { once } from 'node:events'; +import { execFile } from 'node:child_process'; +import { promisify } from 'node:util'; +import { access, readFile } from 'node:fs/promises'; +import { constants } from 'node:fs'; +const run = promisify(execFile), secret = 'fixture-image-credential-' + process.pid; +const state = process.env.T3CODE_HOME || '/home/t3/.t3'; +const key = process.env.T3_SETUP_KEY || (await readFile(state + '/setup-key', 'utf8')).trim(); +const port = process.env.T3_SETUP_PORT || '3774'; +const request = async (route, body) => { + const response = await fetch('http://127.0.0.1:' + port + route, { method: body === undefined ? 'GET' : 'POST', headers: { 'x-t3-setup-key': key, 'content-type': 'application/json' }, body: body === undefined ? undefined : JSON.stringify(body) }); + const text = await response.text(); assert.equal(text.includes(secret), false); assert.equal(response.status, 200, text); return JSON.parse(text); +}; +const server = createServer((req, res) => { + assert.equal(req.headers.authorization, 'Bearer ' + secret); + res.end(JSON.stringify({ status: 'ok', echo: secret })); +}); +server.listen(0, '127.0.0.1'); await once(server, 'listening'); +const id = 'smoke-credential-' + process.pid; +let created = false; +try { + await access('/opt/t3-setup/credentials/askpass.sh', constants.X_OK); + for (const cli of ['t3-ssh', 't3-api']) assert.match((await run('/usr/local/bin/' + cli, ['--help'])).stdout, /Manage connections/); + let snapshot = await request('/credentials'); + await request('/credentials/create', { revision: snapshot.revision, profile: { id, label: 'Disposable image check', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } }); + created = true; snapshot = await request('/credentials'); + assert.equal(snapshot.profiles.find(profile => profile.id === id).hasSecret, true); + await request('/credentials/test', { id, revision: snapshot.revision }); + const { stdout, stderr } = await run('/usr/local/bin/t3-api', [id, 'GET', 'states']); + assert.deepEqual(JSON.parse(stdout), { status: 'ok', echo: '[redacted]' }); assert.equal(stderr, ''); + console.log('PASS saved API credentials and installed SSH/API helpers'); +} finally { + try { if (created) { const snapshot = await request('/credentials'); await request('/credentials/remove', { id, revision: snapshot.revision }); } } + finally { server.closeAllConnections(); await new Promise(resolve => server.close(resolve)); } +} diff --git a/scripts/credentials-ui-audit.mjs b/scripts/credentials-ui-audit.mjs new file mode 100644 index 00000000..82865a12 --- /dev/null +++ b/scripts/credentials-ui-audit.mjs @@ -0,0 +1,114 @@ +#!/usr/bin/env node +// Real credential API + disposable home; no real server or credential is used. +import assert from 'node:assert/strict'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import { createRequire } from 'node:module'; +import { credentialsFixture } from '../tests/fixtures/credentials.mjs'; +const require = createRequire(import.meta.url); +let chromium; +try { ({ chromium } = require('playwright')); } catch { ({ chromium } = require('playwright-core')); } +const { statusFor, portsFor, fixture, framed } = require('./lib/console-fixtures.cjs'); +const output = process.env.T3_CREDENTIALS_UI_OUTPUT || '/tmp/t3-credentials-ui'; +await fs.mkdir(output, { recursive: true }); +const f = await credentialsFixture(); +const browser = await chromium.launch({ executablePath: process.env.CHROME_PATH || '/usr/bin/chromium', args: ['--no-sandbox'] }); +const secret = 'fixture-browser-password-123', token = 'fixture-browser-token-456'; +try { + for (const theme of ['light', 'dark']) for (const [width, height, embedded] of [[360, 720], [390, 844], [820, 900], [1280, 900], [1198, 878, true]].filter(size => !process.env.T3_CREDENTIALS_UI_WIDTH || size[0] === Number(process.env.T3_CREDENTIALS_UI_WIDTH))) { + console.log(`Checking ${theme} ${width}x${height}${embedded ? ' embedded' : ''}`); + for (const profile of (await (await f.request('/credentials')).json()).profiles) { + const current = await (await f.request('/credentials')).json(); + assert.equal((await f.request('/credentials/remove', { id: profile.id, revision: current.revision })).status, 200); + } + const page = await browser.newPage({ viewport: { width, height }, colorScheme: theme, reducedMotion: 'reduce' }); + const errors = [], responses = []; page.on('pageerror', error => errors.push(error.message)); + page.on('response', response => { if (/\/credentials(?:\/|$)/.test(new URL(response.url()).pathname)) responses.push(response.text().catch(() => '')); }); + await page.addInitScript(value => localStorage.setItem('t3-console-theme', value), theme); + await page.route('**/*', route => { + const url = new URL(route.request().url()); + if (url.pathname.endsWith('/status')) return route.fulfill({ json: statusFor('ready') }); + if (url.pathname.endsWith('/providers')) return route.fulfill({ json: fixture('providers.json') }); + if (url.pathname.endsWith('/ports')) return route.fulfill({ json: portsFor('ready') }); + return route.continue(); + }); + const url = f.base + '/' + (embedded ? '?embed=t3&theme=' + theme : '') + '#credentials'; + const target = embedded ? await framed(page, url) : (await page.goto(url), page); + await target.getByLabel('Setup key', { exact: true }).fill('credential-fixture-key'); + await target.getByRole('button', { name: 'Unlock', exact: true }).click(); + await target.getByText('Save a connection once', { exact: true }).waitFor(); + const capture = step => page.screenshot({ path: path.join(output, `${theme}-${width}${embedded ? '-embedded' : ''}-${step}.png`), fullPage: true }); + await capture('empty'); + const dialog = target.getByRole('dialog'); + const add = async (id, label, type = 'ssh') => { + await target.getByRole('button', { name: 'Add connection', exact: true }).first().click(); + await dialog.waitFor(); await target.getByLabel('Name', { exact: true }).fill(label); + await target.getByLabel('Connection ID', { exact: true }).fill(id); + await target.getByLabel('Connection type').selectOption(type); + if (type === 'ssh') { await target.getByLabel('Host', { exact: true }).fill('192.0.2.10'); await target.getByLabel('Username', { exact: true }).fill(id === 'homeserver' ? 'oliver' : 'root'); } + else await target.getByLabel('API base URL').fill('http://192.0.2.20/api/'); + await target.locator('#credential-secret').fill(type === 'ssh' ? secret : token); + await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); + await dialog.waitFor({ state: 'hidden' }); await target.locator(`[data-key="credential-${id}"]`).waitFor(); + }; + await add('homeserver', 'HomeServer'); await add('homeassistant-ssh', 'Home Assistant SSH'); await add('homeassistant', 'Home Assistant API', 'api'); + await capture('saved'); + assert.equal((await target.content()).includes(secret), false); + assert.equal((await target.content()).includes(token), false); + await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).click(); + assert.equal(await target.locator('#credential-secret').inputValue(), ''); + assert.equal(await target.getByLabel('Connection ID', { exact: true }).isDisabled(), true); + assert.equal(await target.getByLabel('Connection type').isDisabled(), true); + const box = await dialog.boundingBox(); + assert.ok(box.x >= -1 && box.y >= -1 && box.x + box.width <= width + 1 && box.y + box.height <= height + 1); + const buttons = await dialog.getByRole('button', { name: 'Save connection', exact: true }).boundingBox(); + assert.ok(buttons.y + buttons.height <= height, 'Save stays visible while fields scroll'); + await capture('edit'); + // An overlapping editor must not silently replace another window's edit. + const current = await (await f.request('/credentials')).json(); + const old = current.profiles.find(profile => profile.id === 'homeserver'); + await f.request('/credentials/save', { profile: { ...old, label: 'Updated elsewhere' }, revision: current.revision }); + await target.locator('#credential-secret').fill('replacement-fixture-password'); + await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); + await target.getByRole('alert').waitFor(); + assert.equal(await target.locator('#credential-secret').inputValue(), 'replacement-fixture-password'); + assert.equal((await target.getByRole('alert').innerText()).includes('replacement-fixture-password'), false); + assert.equal(await target.locator('#credential-error').evaluate(el => document.activeElement === el), true); + await capture('conflict'); + await dialog.getByRole('button', { name: 'Cancel', exact: true }).click(); + await target.getByRole('button', { name: 'Reload', exact: true }).click(); + await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).waitFor(); + await target.getByRole('button', { name: 'Edit Updated elsewhere', exact: true }).click(); + await target.getByLabel('Name', { exact: true }).fill('HomeServer'); + // Saving twice while the request is pending still issues exactly one write. + let release, started, saves = 0; + const gate = new Promise(resolve => { release = resolve; }); + const arrived = new Promise(resolve => { started = resolve; }); + const intercept = async route => { saves++; started(); await gate; await route.continue(); }; + await page.route('**/credentials/save', intercept); + await dialog.getByRole('button', { name: 'Save connection', exact: true }).click(); + await Promise.race([arrived, new Promise((_, reject) => setTimeout(() => reject(new Error('Save request did not start: ' + theme + ' ' + width)), 5000).unref())]); + await target.locator('#credential-secret').press('Enter'); await page.keyboard.press('Escape'); + assert.equal(await dialog.count(), 1); assert.equal(await dialog.getByRole('button', { name: 'Cancel', exact: true }).isDisabled(), true); + release(); await dialog.waitFor({ state: 'hidden' }); await page.unroute('**/credentials/save', intercept); + assert.equal(saves, 1); await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).waitFor(); + await page.route('**/credentials/test', route => route.fulfill({ json: { ok: true, message: 'Connection succeeded.' } })); + await target.getByRole('button', { name: 'Test Home Assistant API', exact: true }).click(); + await target.getByText('Connection succeeded', { exact: true }).waitFor(); + const failRead = route => route.fulfill({ status: 500, json: { ok: false, error: 'Fixture read failed.' } }); + await page.route('**/credentials', failRead); + await target.getByRole('button', { name: 'Reload', exact: true }).click(); await target.getByRole('alert').waitFor(); + assert.equal(await target.getByRole('button', { name: 'Edit HomeServer', exact: true }).isDisabled(), true); + await capture('read-error'); await page.unroute('**/credentials', failRead); + await target.getByRole('button', { name: 'Reload', exact: true }).click(); + await target.getByRole('button', { name: 'Delete Home Assistant SSH', exact: true }).click(); + await target.getByRole('alertdialog').getByRole('button', { name: 'Delete connection', exact: true }).click(); + await target.locator('[data-key="credential-homeassistant-ssh"]').waitFor({ state: 'hidden' }); + assert.equal(await target.evaluate(() => document.documentElement.scrollWidth > innerWidth), false); + for (const response of await Promise.all(responses)) for (const value of [secret, token, 'replacement-fixture-password']) assert.equal(response.includes(value), false); + assert.deepEqual(errors, []); await capture('after-delete'); + console.log(`PASS server credentials: ${theme} ${width}x${height}${embedded ? ' embedded' : ''}`); + await page.close(); + } + assert.equal(f.logs().includes(secret), false); assert.equal(f.logs().includes(token), false); +} finally { await browser.close(); await f.close(); } diff --git a/scripts/fixtures/console/credentials.json b/scripts/fixtures/console/credentials.json new file mode 100644 index 00000000..5aa06ff5 --- /dev/null +++ b/scripts/fixtures/console/credentials.json @@ -0,0 +1,9 @@ +{ + "ok": true, + "revision": "fixture-credentials", + "profiles": [ + { "id": "homeserver", "label": "HomeServer", "type": "ssh", "host": "192.0.2.10", "username": "oliver", "port": 22, "hasSecret": true }, + { "id": "homeassistant-ssh", "label": "Home Assistant SSH", "type": "ssh", "host": "192.0.2.20", "username": "root", "port": 22, "hasSecret": true }, + { "id": "homeassistant", "label": "Home Assistant API", "type": "api", "baseUrl": "http://192.0.2.20/api/", "hasSecret": true } + ] +} diff --git a/scripts/lib/console-fixtures.cjs b/scripts/lib/console-fixtures.cjs index 82457816..f17e74a2 100644 --- a/scripts/lib/console-fixtures.cjs +++ b/scripts/lib/console-fixtures.cjs @@ -127,6 +127,7 @@ const routeConsole = async (page, { status, ports, skillOptions, downloadHTTP = if (at("/status")) return route.fulfill({ json: status() }); if (at("/ports")) return route.fulfill({ json: ports() }); if (at("/providers")) return route.fulfill({ json: fixture("providers.json") }); + if (at("/credentials")) return route.fulfill({ json: fixture("credentials.json") }); return route.continue(); }); }; diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 0bfc92e4..d5b99a66 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -161,6 +161,13 @@ check "no harness executable is baked, only the root-owned dispatcher" only_the_ check "mise ships" "docker exec $NAME mise --version" check "harness installer ships" "docker exec $NAME t3-harness --help" check "storage CLI ships" "docker exec $NAME t3-storage --help" +check "SSH credential helper ships" "docker exec $NAME t3-ssh --help" +check "API credential helper ships" "docker exec $NAME t3-api --help" +credentials_roundtrip() { + docker cp "$SCRIPT_DIR/credentials-smoke.mjs" "$NAME:/tmp/t3-credentials-smoke.mjs" >/dev/null + docker exec -u t3 "$NAME" node /tmp/t3-credentials-smoke.mjs +} +check "saved credentials stay private through the setup API and installed helpers" credentials_roundtrip storage_cli_has_disk() { local output output="$(docker exec "$NAME" t3-storage status --json)" || return 1 diff --git a/tests/credentials-api.test.mjs b/tests/credentials-api.test.mjs new file mode 100644 index 00000000..679cf275 --- /dev/null +++ b/tests/credentials-api.test.mjs @@ -0,0 +1,75 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { createServer } from 'node:http'; +import { once } from 'node:events'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { credentialsFixture } from './fixtures/credentials.mjs'; + +test('credential HTTP boundary is authenticated, write-only and revision checked', { timeout: 20000 }, async t => { + const f = await credentialsFixture(); t.after(f.close); + for (const route of ['/credentials', '/credentials/create', '/credentials/save', '/credentials/test', '/credentials/remove']) { + const method = route === '/credentials' ? 'GET' : 'POST'; + assert.equal((await fetch(f.base + route, { method })).status, 401); + } + assert.equal((await f.request('/credentials/create', {}, { 'sec-fetch-site': 'cross-site' })).status, 403); + assert.equal((await f.request('/credentials', {})).status, 405); + assert.equal((await f.request('/credentials/create')).status, 405); + const initial = await (await f.request('/credentials')).json(); + assert.deepEqual(initial.profiles, []); + const secret = 'fixture-http-credential-456'; + const profile = { id: 'homeassistant-ssh', label: 'Home Assistant SSH', type: 'ssh', host: '192.0.2.2', username: 'root', port: 22, secret }; + const created = await (await f.request('/credentials/create', { profile, revision: initial.revision })).json(); + assert.equal(created.ok, true); assert.equal(JSON.stringify(created).includes(secret), false); + const snapshotResponse = await f.request('/credentials'); + assert.equal(snapshotResponse.headers.get('cache-control'), 'no-store'); + const snapshot = await snapshotResponse.json(); assert.equal(JSON.stringify(snapshot).includes(secret), false); + assert.equal(snapshot.profiles[0].hasSecret, true); + assert.equal((await f.request('/credentials/save', { profile, revision: initial.revision })).status, 409); + assert.equal((await f.request('/credentials/create', { profile, revision: snapshot.revision })).status, 409); + assert.equal((await f.request('/credentials/save', { profile: { ...profile, secret: '' }, revision: snapshot.revision })).status, 200); + const malformed = await fetch(f.base + '/credentials/create', { method: 'POST', headers: { 'x-t3-setup-key': 'credential-fixture-key' }, body: '{"secret":"' + secret }); + assert.equal(malformed.status, 400); assert.equal((await malformed.text()).includes(secret), false); + const oversized = await fetch(f.base + '/credentials/create', { method: 'POST', headers: { 'x-t3-setup-key': 'credential-fixture-key' }, body: JSON.stringify({ secret: secret.repeat(4000) }) }); + assert.equal(oversized.status, 413); assert.equal((await oversized.text()).includes(secret), false); + assert.equal((await f.request('/credentials/create', null)).status, 400); + const latest = await (await f.request('/credentials')).json(); + assert.equal((await f.request('/credentials/test', { id: profile.id, revision: initial.revision })).status, 409); + assert.equal((await f.request('/credentials/remove', { id: profile.id, revision: latest.revision })).status, 200); + assert.deepEqual((await (await f.request('/credentials')).json()).profiles, []); + assert.equal(f.logs().includes(secret), false); +}); + +test('saved HA token works through the CLI and connection test without returning the token', { timeout: 20000 }, async t => { + const f = await credentialsFixture(); t.after(f.close); + const secret = 'fixture-api-token-789'; let target, failAuth = false; + const server = createServer(async (req, res) => { + assert.equal(req.headers.authorization, 'Bearer ' + secret); + const chunks = []; for await (const chunk of req) chunks.push(chunk); + target = { url: req.url, method: req.method, body: Buffer.concat(chunks).toString() }; + if (failAuth) { res.writeHead(401); res.end(secret); return; } + res.end(JSON.stringify({ message: secret, ok: true })); + }); + server.listen(0, '127.0.0.1'); await once(server, 'listening'); + t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); + const initial = await (await f.request('/credentials')).json(); + const saved = await (await f.request('/credentials/create', { revision: initial.revision, profile: { id: 'homeassistant', label: 'Home Assistant API', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret } })).json(); + const probe = await f.request('/credentials/test', { id: 'homeassistant', revision: saved.revision }); + assert.equal(probe.status, 200); assert.equal((await probe.text()).includes(secret), false); + failAuth = true; + const rejected = await f.request('/credentials/test', { id: 'homeassistant', revision: saved.revision }); + assert.equal(rejected.status, 502); assert.equal((await rejected.text()).includes(secret), false); + failAuth = false; + const helperEnv = { ...f.env, T3_INFRA_NODE: process.execPath, T3_CREDENTIAL_CLI: fileURLToPath(new URL('../docker/setup/credentials/cli.mjs', import.meta.url)) }; + const child = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-api', import.meta.url)), 'homeassistant', 'POST', 'services/light/turn_on', '--stdin'], { env: helperEnv, stdio: ['pipe', 'pipe', 'pipe'] }); + let out = '', err = ''; child.stdout.on('data', chunk => { out += chunk; }); child.stderr.on('data', chunk => { err += chunk; }); + child.stdin.end('{"entity_id":"light.kitchen"}'); + const [code] = await once(child, 'close'); + assert.equal(code, 0, err); assert.equal(err, ''); + assert.deepEqual(JSON.parse(out), { message: '[redacted]', ok: true }); + assert.deepEqual(target, { url: '/api/services/light/turn_on', method: 'POST', body: '{"entity_id":"light.kitchen"}' }); + const help = spawn('/bin/bash', [fileURLToPath(new URL('../docker/bin/t3-ssh', import.meta.url)), '--help'], { env: helperEnv, stdio: ['ignore', 'pipe', 'pipe'] }); + let helpText = ''; help.stdout.on('data', chunk => { helpText += chunk; }); + assert.equal((await once(help, 'close'))[0], 0); assert.match(helpText, /t3-ssh CONNECTION/); + assert.equal(f.logs().includes(secret), false); +}); diff --git a/tests/credentials.test.mjs b/tests/credentials.test.mjs new file mode 100644 index 00000000..c6e313f4 --- /dev/null +++ b/tests/credentials.test.mjs @@ -0,0 +1,151 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { createServer } from 'node:http'; +import { once } from 'node:events'; +import { spawn } from 'node:child_process'; +import { createCredentialStore, credentialFailure } from '../docker/setup/credentials.mjs'; +import { outputFilter, apiRequest, apiTarget, sshRequest, testCredential } from '../docker/setup/credentials/run.mjs'; + +const secret = 'fixture-private-credential-123'; +const ssh = { id: 'homeserver', label: 'Home server', type: 'ssh', host: '192.0.2.1', username: 'oliver', port: 22, secret }; +async function fixture(t) { + const root = await fs.mkdtemp(path.join(os.tmpdir(), 't3-credentials-')); + const directory = path.join(root, 'credentials'); + t.after(() => fs.rm(root, { recursive: true, force: true })); + return { root, directory, store: createCredentialStore({ directory }) }; +} +const create = async (store, profile) => store.save({ profile, revision: (await store.list()).revision, create: true }); + +test('credentials persist privately and public reads never include saved values', async t => { + const { directory, store } = await fixture(t); + await create(store, ssh); + await create(store, { id: 'ha', label: 'Home Assistant API', type: 'api', baseUrl: 'http://192.0.2.2/api', secret: secret + '-token' }); + const snapshot = await createCredentialStore({ directory }).list(); + assert.equal(snapshot.profiles.length, 2); + assert.equal(snapshot.profiles[1].baseUrl, 'http://192.0.2.2/api/'); + assert.equal(JSON.stringify(snapshot).includes(secret), false); + assert.equal((await store.forUse('homeserver')).secret, secret); + assert.equal((await fs.stat(directory)).mode & 0o777, 0o700); + assert.equal((await fs.stat(path.join(directory, 'credentials.json'))).mode & 0o777, 0o600); + const saved = await store.save({ profile: { ...ssh, secret: '', label: 'Renamed' }, revision: snapshot.revision }); + assert.equal((await store.forUse('homeserver')).secret, secret); + assert.equal(JSON.stringify(saved).includes(secret), false); + await store.save({ profile: { ...ssh, secret: 'replacement-password' }, revision: saved.revision }); + assert.equal((await store.forUse('homeserver')).secret, 'replacement-password'); + await store.remove({ id: 'homeserver', revision: (await store.list()).revision }); + await assert.rejects(store.forUse('homeserver'), /not found/); + assert.equal((await store.list()).profiles.length, 1); +}); + +test('conflicting, duplicate and overlapping writes cannot overwrite another editor', async t => { + const { store } = await fixture(t); + const before = await store.list(); + await create(store, ssh); + await assert.rejects(store.save({ profile: { ...ssh, secret: 'lost' }, revision: before.revision }), { status: 409 }); + let revision = (await store.list()).revision; + await assert.rejects(store.save({ profile: ssh, revision, create: true }), { status: 409 }); + const outcomes = await Promise.allSettled(['First', 'Second'].map(label => store.save({ profile: { ...ssh, label }, revision }))); + assert.deepEqual(outcomes.map(outcome => outcome.status), ['fulfilled', 'rejected']); + assert.equal(outcomes[1].reason.status, 409); + revision = (await store.list()).revision; + await assert.rejects(store.remove({ id: 'homeserver', revision: before.revision }), { status: 409 }); + assert.equal((await store.forUse('homeserver')).label, 'First'); +}); + +test('invalid input and damaged stores fail without echoing or replacing credentials', async t => { + const { directory, root, store } = await fixture(t); + for (const change of [{ id: '../escape' }, { host: '-oProxyCommand=bad' }, { username: 'user;bad' }, { port: 0 }, { secret: 'line\nbreak' }, { secret: '\ud800' }, { secret: undefined }, { label: '\u0000' }, { type: 'unknown' }]) { + await assert.rejects(create(store, { ...ssh, ...change })); + } + for (const baseUrl of ['file:///etc/passwd', 'https://user:password@example.com', 'http://example.com?secret=hello', 'http://example.com/#secret']) { + await assert.rejects(create(store, { id: 'api', label: 'API', type: 'api', baseUrl, secret })); + } + await create(store, ssh); + const file = path.join(directory, 'credentials.json'); + await fs.writeFile(file, '{"secret":"' + secret + '"'); + let failure; + try { await store.list(); } catch (error) { failure = credentialFailure(error); } + assert.equal(failure.status, 500); assert.equal(JSON.stringify(failure).includes(secret), false); + await assert.rejects(create(store, ssh)); + assert.equal(await fs.readFile(file, 'utf8'), '{"secret":"' + secret + '"'); + await fs.rm(file); + const external = path.join(root, 'external'); await fs.writeFile(external, 'do not touch'); + await fs.symlink(external, file); await assert.rejects(store.list()); + assert.equal(await fs.readFile(external, 'utf8'), 'do not touch'); + await fs.rm(directory, { recursive: true }); await fs.symlink(root, directory); + await assert.rejects(store.list()); +}); + +test('output filtering masks literal and encoded values across every chunk boundary', () => { + for (const value of [secret, 'password-with-"quotes"&slashes\\and-more']) { + const variants = [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value), Buffer.from(value).toString('base64')]; + const source = 'before ' + variants.join(' middle ') + ' after'; + for (let size = 1; size <= source.length; size++) { + let output = ''; const filter = outputFilter(value, text => { output += text; }); + for (let i = 0; i < source.length; i += size) filter.write(source.slice(i, i + size)); + filter.end(); + assert.equal(output, 'before ' + variants.map(() => '[redacted]').join(' middle ') + ' after', 'chunk size ' + size); + } + } +}); + +test('API helper authenticates internally, filters output and never follows redirects', async t => { + let calls = 0, received; + const server = createServer(async (req, res) => { + calls++; assert.equal(req.headers.authorization, 'Bearer ' + secret); + const chunks = []; for await (const chunk of req) chunks.push(chunk); + received = { url: req.url, method: req.method, body: Buffer.concat(chunks).toString() }; + if (req.url === '/api/redirect') { res.writeHead(302, { location: '/elsewhere' }); res.end(); return; } + if (req.url === '/api/unauthorized') { res.writeHead(401); res.end(secret); return; } + res.write('hello ' + secret.slice(0, 8)); setTimeout(() => res.end(secret.slice(8) + ' goodbye'), 5); + }); + server.listen(0, '127.0.0.1'); await once(server, 'listening'); + t.after(() => new Promise(resolve => { server.closeAllConnections(); server.close(resolve); })); + const profile = { id: 'ha', type: 'api', baseUrl: 'http://127.0.0.1:' + server.address().port + '/api/', secret }; + let output = ''; + assert.equal(await apiRequest(profile, 'POST', 'services/light/turn_on', { body: '{"entity_id":"light.kitchen"}', stdout: { write: text => { output += text; } } }), 0); + assert.equal(output, 'hello [redacted] goodbye'); + assert.deepEqual(received, { url: '/api/services/light/turn_on', method: 'POST', body: '{"entity_id":"light.kitchen"}' }); + await assert.rejects(apiRequest(profile, 'GET', 'redirect'), /redirects are not followed/); + assert.equal(calls, 2, 'redirect destination was never requested'); + await assert.rejects(apiRequest(profile, 'GET', 'unauthorized', { probe: true }), error => !error.message.includes(secret) && /HTTP 401/.test(error.message)); + assert.equal(await testCredential(profile), 0); + const cancelled = new AbortController(); cancelled.abort(); + await assert.rejects(testCredential(profile, { signal: cancelled.signal }), /API request failed/); + for (const target of ['https://other.test/api', '//other.test', '/api/states', '../outside', '%2e%2e/outside', 'foo\\outside', '#fragment']) assert.throws(() => apiTarget(profile, target)); +}); + +test('SSH helper supplies askpass privately and filters both output streams', async t => { + const { root } = await fixture(t); + const fixtureFile = path.join(root, 'ssh.cjs'); + await fs.writeFile(fixtureFile, `const {execFileSync}=require('node:child_process'); +const secret=execFileSync(process.env.SSH_ASKPASS,[],{encoding:'utf8'}).trimEnd(); +if(secret!==process.env.T3_CREDENTIAL_PASSWORD)process.exit(2); +process.stdout.write('output '+secret.slice(0,5)); +process.stderr.write('error '+secret.slice(0,5)); +setTimeout(()=>{process.stdout.write(secret.slice(5)+' done');process.stderr.write(secret.slice(5)+' done');},10);`); + let out = '', err = ''; + const code = await sshRequest(ssh, ['uptime'], { stdin: 'ignore', stdout: { write: value => { out += value; } }, stderr: { write: value => { err += value; } }, + spawnProcess: (executable, args, options) => { + assert.equal(executable, '/usr/bin/ssh'); assert.ok(args.includes('StrictHostKeyChecking=accept-new')); + assert.equal(JSON.stringify(args).includes(secret), false); + assert.deepEqual(args.slice(-2), ['192.0.2.1', 'uptime']); + return spawn(process.execPath, [fixtureFile], options); + }, + }); + assert.equal(code, 0); assert.equal(out, 'output [redacted] done'); assert.equal(err, 'error [redacted] done'); + const controller = new AbortController(); let interrupted; + t.after(() => interrupted?.kill()); + await assert.rejects(sshRequest(ssh, ['true'], { stdin: 'ignore', signal: controller.signal, + spawnProcess: (_executable, _args, options) => { + interrupted = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1000)'], options); + interrupted.once('spawn', () => controller.abort()); + return interrupted; + }, + }), /SSH could not start or was interrupted/); + if (interrupted.signalCode === null && interrupted.exitCode === null) await once(interrupted, 'close'); + assert.equal(interrupted.signalCode, 'SIGTERM'); +}); diff --git a/tests/files-paths.test.mjs b/tests/files-paths.test.mjs index a5c644e2..d8fad02c 100644 --- a/tests/files-paths.test.mjs +++ b/tests/files-paths.test.mjs @@ -67,3 +67,13 @@ test('managed ancestors are explained without locking unrelated sibling content' const caches = createPathPolicy({ home: f.home, workspace: f.workspace, env: {}, storage: { snapshot: () => ({ categories: [{ kind: 'cache', path: path.join(f.root, 'custom-cache') }] }) } }); assert.equal((await caches.classify(path.join(f.root, 'custom-cache/entry'))).managed.tag, 'Caches'); }); + +test('saved server credentials carry key and secret warnings in Files, including a custom state volume', async t => { + const f = await fixture(t); + const policy = createPathPolicy({ home: f.home, workspace: f.workspace, env: { T3CODE_HOME: path.join(f.root, 'custom-t3') } }); + const folder = path.join(f.root, 'custom-t3/server-credentials'); + await fs.mkdir(folder, { recursive: true }); + assert.equal((await policy.classify(folder)).keys, true); + const file = await policy.classify(path.join(folder, 'credentials.json')); + assert.equal(file.keys, true); assert.equal(file.secret, true); +}); diff --git a/tests/fixtures/credentials.mjs b/tests/fixtures/credentials.mjs new file mode 100644 index 00000000..f86db578 --- /dev/null +++ b/tests/fixtures/credentials.mjs @@ -0,0 +1,37 @@ +// Real setup API in an empty disposable home, shared by HTTP and UI checks. +import * as fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; +import { spawn } from 'node:child_process'; +import { once } from 'node:events'; +import { createServer } from 'node:net'; +import { fileURLToPath } from 'node:url'; + +export async function credentialsFixture() { + const home = await fs.mkdtemp(path.join(os.tmpdir(), 't3-server-credentials-')); + const reservation = createServer().listen(0, '127.0.0.1'); + await once(reservation, 'listening'); const port = reservation.address().port; + await new Promise(resolve => reservation.close(resolve)); + const env = { ...process.env, HOME: home, T3CODE_HOME: path.join(home, '.t3'), T3_WORKSPACE: path.join(home, 'workspace'), + CODEX_HOME: path.join(home, '.codex'), CLAUDE_CONFIG_DIR: path.join(home, '.claude'), XDG_CONFIG_HOME: path.join(home, '.config'), XDG_DATA_HOME: path.join(home, '.local/share'), + MISE_DATA_DIR: path.join(home, '.local/share/mise'), MISE_STATE_DIR: path.join(home, '.local/state/mise'), MISE_CONFIG_DIR: path.join(home, '.config/mise'), + T3_SETUP_PORT: String(port), T3_SETUP_KEY: 'credential-fixture-key', T3_SETUP_KEY_SOURCE: 'env', T3_INFRA_LAUNCHER: '/bin/false', T3CODE_PORT: '1', T3_SETUP_ACCEPT_T3_SESSIONS: '0' }; + const child = spawn(process.execPath, [fileURLToPath(new URL('../../docker/setup/server.mjs', import.meta.url))], { env, stdio: ['ignore', 'pipe', 'pipe'] }); + let logs = ''; child.stdout.on('data', chunk => { logs += chunk; }); child.stderr.on('data', chunk => { logs += chunk; }); + const closed = once(child, 'close'), base = 'http://127.0.0.1:' + port + '/__setup'; + const request = (route, body, headers = {}) => fetch(base + route, { + method: body === undefined ? 'GET' : 'POST', headers: { 'x-t3-setup-key': 'credential-fixture-key', ...(body === undefined ? {} : { 'content-type': 'application/json' }), ...headers }, body: body === undefined ? undefined : JSON.stringify(body), + }); + const close = async () => { + if (child.exitCode === null && child.signalCode === null) child.kill(); + await closed; await fs.rm(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 }); + }; + try { + for (let i = 0; i < 200; i++) { + if (child.exitCode !== null || child.signalCode !== null) throw new Error(logs); + try { if ((await request('/hello')).ok) return { home, env, base, request, close, logs: () => logs }; } catch {} + await new Promise(resolve => setTimeout(resolve, 20)); + } + throw new Error('Credential fixture did not start.'); + } catch (error) { await close(); throw error; } +} From e650ee0b11afcd63f51a04d9e92591f1a83bae9c Mon Sep 17 00:00:00 2001 From: 0libote <79215282+0libote@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:13:59 +0000 Subject: [PATCH 2/8] docs: keep credential screenshots in the PR description --- docs/media/server-credentials/desktop.png | Bin 357240 -> 0 bytes docs/media/server-credentials/phone-editor.png | Bin 55037 -> 0 bytes docs/server-credentials.md | 2 -- 3 files changed, 2 deletions(-) delete mode 100644 docs/media/server-credentials/desktop.png delete mode 100644 docs/media/server-credentials/phone-editor.png diff --git a/docs/media/server-credentials/desktop.png b/docs/media/server-credentials/desktop.png deleted file mode 100644 index eba84abbf454677cfe56c4dd92f7f88746bbd20e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357240 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 z 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 G0sjZjlgqaN diff --git a/docs/media/server-credentials/phone-editor.png b/docs/media/server-credentials/phone-editor.png deleted file mode 100644 index 3baa724e8d2462105d662c3230650fb1542d9006..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55037 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