HarborSSH 0.1.0 — delivery verification
Date: September 13, 2026
Environment: Linux; Node.js v22.16.0; TypeScript 5.8.3

BUILD: npm run build — PASS (strict TypeScript compilation)
JAVASCRIPT: node --check web/app.js — PASS
LAUNCHER: ./harborssh help — PASS
AUTOMATED TESTS: 56 total; 55 passed; 0 failed; 1 skipped.
SKIPPED: Explicit opt-in real SSH test. No ssh/sshd binaries or authorized host
were available in this environment. Fake executors are confined to test fixtures.

HTTP/OAUTH: Real local Node HTTP listeners were tested, including OAuth consent,
PKCE exchange, MCP tool use, separate local approval and simulated output retrieval.
SSH ADAPTER: Tested with an actual Node child process fixture, NOT an SSH handshake.
BROWSER: Optional Chromium UI test attempted but blocked by environment policy:
ERR_BLOCKED_BY_ADMINISTRATOR on the local fixture URL. No UI/browser pass claimed.
NOT PERFORMED: Real SSH, real ChatGPT connection, external HTTPS tunnel, public
plugin registration/publication, cross-platform CI, independent security audit.

Full Node test output follows.


> harborssh@0.1.0 test
> node --test --test-concurrency=1 tests/*.test.mjs

TAP version 13
# Subtest: discovery advertises S256, resource audience, DCR and issuer identification
ok 1 - discovery advertises S256, resource audience, DCR and issuer identification
  ---
  duration_ms: 4.66644
  type: 'test'
  ...
# Subtest: DCR rejects callback wildcards and unrelated destinations
ok 2 - DCR rejects callback wildcards and unrelated destinations
  ---
  duration_ms: 1.694637
  type: 'test'
  ...
# Subtest: DCR rejects unsupported grants and client-auth methods
ok 3 - DCR rejects unsupported grants and client-auth methods
  ---
  duration_ms: 1.081569
  type: 'test'
  ...
# Subtest: authorization cannot omit S256 or change resource audience
ok 4 - authorization cannot omit S256 or change resource audience
  ---
  duration_ms: 3.563998
  type: 'test'
  ...
# Subtest: consent binds its request, CSRF and browser cookie
ok 5 - consent binds its request, CSRF and browser cookie
  ---
  duration_ms: 2.916424
  type: 'test'
  ...
# Subtest: consent callback includes exact issuer and state
ok 6 - consent callback includes exact issuer and state
  ---
  duration_ms: 2.64286
  type: 'test'
  ...
# Subtest: denied consent still supplies issuer and original state
ok 7 - denied consent still supplies issuer and original state
  ---
  duration_ms: 2.011282
  type: 'test'
  ...
# Subtest: pairing code is single use and never grants an access token directly
ok 8 - pairing code is single use and never grants an access token directly
  ---
  duration_ms: 2.37649
  type: 'test'
  ...
# Subtest: authorization code exchange validates PKCE and is single use
ok 9 - authorization code exchange validates PKCE and is single use
  ---
  duration_ms: 3.466361
  type: 'test'
  ...
# Subtest: bad PKCE consumes the authorization code
ok 10 - bad PKCE consumes the authorization code
  ---
  duration_ms: 3.280335
  type: 'test'
  ...
# Subtest: token cannot be exchanged for a different client or resource
ok 11 - token cannot be exchanged for a different client or resource
  ---
  duration_ms: 4.771749
  type: 'test'
  ...
# Subtest: refresh rotates tokens and rejects reuse by revoking the token family
ok 12 - refresh rotates tokens and rejects reuse by revoking the token family
  ---
  duration_ms: 3.419001
  type: 'test'
  ...
# Subtest: refresh cannot expand scopes and read tokens cannot execute
ok 13 - refresh cannot expand scopes and read tokens cannot execute
  ---
  duration_ms: 2.434296
  type: 'test'
  ...
# Subtest: client_secret_post and client_secret_basic are authenticated correctly
ok 14 - client_secret_post and client_secret_basic are authenticated correctly
  ---
  duration_ms: 5.422122
  type: 'test'
  ...
# Subtest: OAuth clients and hashed tokens survive restart; plaintext secrets do not persist
ok 15 - OAuth clients and hashed tokens survive restart; plaintext secrets do not persist
  ---
  duration_ms: 2.571015
  type: 'test'
  ...
# Subtest: changing issuer invalidates prior tokens and clients
ok 16 - changing issuer invalidates prior tokens and clients
  ---
  duration_ms: 2.983261
  type: 'test'
  ...
# Subtest: access and pairing expire under an injected clock
ok 17 - access and pairing expire under an injected clock
  ---
  duration_ms: 2.893549
  type: 'test'
  ...
# Subtest: revoke all invalidates every access and refresh token
ok 18 - revoke all invalidates every access and refresh token
  ---
  duration_ms: 2.65594
  type: 'test'
  ...
# Subtest: CLI initializes private state, enrolls a trusted key, exports a credential-free plugin
ok 19 - CLI initializes private state, enrolls a trusted key, exports a credential-free plugin
  ---
  duration_ms: 306.703209
  type: 'test'
  ...
# Subtest: CLI rejects misspelled policy flags instead of silently weakening policy
ok 20 - CLI rejects misspelled policy flags instead of silently weakening policy
  ---
  duration_ms: 165.382293
  type: 'test'
  ...
# Subtest: configuration requires HTTPS except loopback development
ok 21 - configuration requires HTTPS except loopback development
  ---
  duration_ms: 1.456085
  type: 'test'
  ...
# Subtest: configuration rejects root unless explicitly authorized
ok 22 - configuration rejects root unless explicitly authorized
  ---
  duration_ms: 1.920851
  type: 'test'
  ...
# Subtest: configuration forbids arbitrary host-option injection and duplicate aliases
ok 23 - configuration forbids arbitrary host-option injection and duplicate aliases
  ---
  duration_ms: 0.468783
  type: 'test'
  ...
# Subtest: configuration rejects unknown fields and unsafe key expansion paths
ok 24 - configuration rejects unknown fields and unsafe key expansion paths
  ---
  duration_ms: 0.324883
  type: 'test'
  ...
# Subtest: choose exactly one SSH credential source
ok 25 - choose exactly one SSH credential source
  ---
  duration_ms: 0.309355
  type: 'test'
  ...
# Subtest: host key format and fingerprint validate the actual SSH wire key
ok 26 - host key format and fingerprint validate the actual SSH wire key
  ---
  duration_ms: 1.219371
  type: 'test'
  ...
# Subtest: private known_hosts pins explicit aliases
ok 27 - private known_hosts pins explicit aliases
  ---
  duration_ms: 2.283309
  type: 'test'
  ...
# Subtest: shell quoting preserves quotes, substitutions and newlines as an argument
ok 28 - shell quoting preserves quotes, substitutions and newlines as an argument
  ---
  duration_ms: 0.360694
  type: 'test'
  ...
# Subtest: remote command quotes cwd separately from intentional shell program
ok 29 - remote command quotes cwd separately from intentional shell program
  ---
  duration_ms: 0.457856
  type: 'test'
  ...
# Subtest: SSH invocation uses isolated trust and no forwarding, local shell or multiplexing
ok 30 - SSH invocation uses isolated trust and no forwarding, local shell or multiplexing
  ---
  duration_ms: 0.847107
  type: 'test'
  ...
# Subtest: OpenSSH executor adapter captures real child stdout, stderr and exit status
ok 31 - OpenSSH executor adapter captures real child stdout, stderr and exit status
  ---
  duration_ms: 36.551372
  type: 'test'
  ...
# Subtest: output ring enforces bounded memory and absolute cursors
ok 32 - output ring enforces bounded memory and absolute cursors
  ---
  duration_ms: 1.015686
  type: 'test'
  ...
# Subtest: output pagination does not split a complete UTF-8 sequence
ok 33 - output pagination does not split a complete UTF-8 sequence
  ---
  duration_ms: 0.144747
  type: 'test'
  ...
# Subtest: atomic state files have private modes and parse correctly
ok 34 - atomic state files have private modes and parse correctly
  ---
  duration_ms: 1.875744
  type: 'test'
  ...
# Subtest: OAuth form parsing rejects duplicate and prototype-confusing fields
ok 35 - OAuth form parsing rejects duplicate and prototype-confusing fields
  ---
  duration_ms: 0.4184
  type: 'test'
  ...
# Subtest: output holds a UTF-8 character split across SSH chunks until complete
ok 36 - output holds a UTF-8 character split across SSH chunks until complete
  ---
  duration_ms: 0.216117
  type: 'test'
  ...
# Subtest: incomplete UTF-8 at final EOF is reported without losing the cursor
ok 37 - incomplete UTF-8 at final EOF is reported without losing the cursor
  ---
  duration_ms: 0.954906
  type: 'test'
  ...
# Subtest: HTTP discovery, authentication challenge and public/admin separation
ok 38 - HTTP discovery, authentication challenge and public/admin separation
  ---
  duration_ms: 74.04737
  type: 'test'
  ...
# Subtest: Full HTTP OAuth + MCP + owner approval + stdout/stderr + revocation
ok 39 - Full HTTP OAuth + MCP + owner approval + stdout/stderr + revocation
  ---
  duration_ms: 57.520295
  type: 'test'
  ...
# Subtest: MCP HTTP notifications, media types, method and protocol validation
ok 40 - MCP HTTP notifications, media types, method and protocol validation
  ---
  duration_ms: 28.895055
  type: 'test'
  ...
# Subtest: HTTP scopes are enforced, not merely described by tool annotations
ok 41 - HTTP scopes are enforced, not merely described by tool annotations
  ---
  duration_ms: 22.239282
  type: 'test'
  ...
# Subtest: free-form commands never execute before local approval
ok 42 - free-form commands never execute before local approval
  ---
  duration_ms: 20.512914
  type: 'test'
  ...
# Subtest: approval is bound to the displayed immutable digest
ok 43 - approval is bound to the displayed immutable digest
  ---
  duration_ms: 2.504497
  type: 'test'
  ...
# Subtest: the model cannot choose approval mode, credentials, or destination
ok 44 - the model cannot choose approval mode, credentials, or destination
  ---
  duration_ms: 3.338476
  type: 'test'
  ...
# Subtest: same request ID is deduplicated and conflicting payload rejected
ok 45 - same request ID is deduplicated and conflicting payload rejected
  ---
  duration_ms: 4.632955
  type: 'test'
  ...
# Subtest: idempotency is scoped per OAuth client
ok 46 - idempotency is scoped per OAuth client
  ---
  duration_ms: 2.37774
  type: 'test'
  ...
# Subtest: persisted deduplication prevents replay after restart without storing shell text
ok 47 - persisted deduplication prevents replay after restart without storing shell text
  ---
  duration_ms: 5.953871
  type: 'test'
  ...
# Subtest: denial and cancellation before approval never start SSH
ok 48 - denial and cancellation before approval never start SSH
  ---
  duration_ms: 3.962367
  type: 'test'
  ...
# Subtest: approval expires and cannot later be used
ok 49 - approval expires and cannot later be used
  ---
  duration_ms: 1.968328
  type: 'test'
  ...
# Subtest: exact owner-configured auto task can execute; argument overrides cannot
ok 50 - exact owner-configured auto task can execute; argument overrides cannot
  ---
  duration_ms: 3.537759
  type: 'test'
  ...
# Subtest: tasks-only host cannot run arbitrary shell
ok 51 - tasks-only host cannot run arbitrary shell
  ---
  duration_ms: 2.14875
  type: 'test'
  ...
# Subtest: jobs serialize per host and preserve separate stdout/stderr
ok 52 - jobs serialize per host and preserve separate stdout/stderr
  ---
  duration_ms: 3.963009
  type: 'test'
  ...
# Subtest: running cancellation is idempotent and does not claim remote rollback
ok 53 - running cancellation is idempotent and does not claim remote rollback
  ---
  duration_ms: 4.235193
  type: 'test'
  ...
# Subtest: job timeout closes the SSH transport and reports timed_out
ok 54 - job timeout closes the SSH transport and reports timed_out
  ---
  duration_ms: 1102.969846
  type: 'test'
  ...
# Subtest: job limits bound pending approvals and output memory
ok 55 - job limits bound pending approvals and output memory
  ---
  duration_ms: 6.896201
  type: 'test'
  ...
# Subtest: LIVE OpenSSH: verified host, remote shell, stdout, stderr and exit status
ok 56 - LIVE OpenSSH: verified host, remote shell, stdout, stderr and exit status # SKIP Set HARBORSSH_LIVE_HOST to an explicitly authorized test-host profile.
  ---
  duration_ms: 0.668787
  type: 'test'
  ...
1..56
# tests 56
# suites 0
# pass 55
# fail 0
# cancelled 0
# skipped 1
# todo 0
# duration_ms 2390.925208
