feat(automation): support qualified single-user Windows operation
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
# Autonomous Jobjakt backlog controller
|
||||
|
||||
**For your normal Windows login and existing ChatGPT account, use [single-user setup](SINGLE_USER.md).** It requires no second Windows account, subscription or VM. The new default is an operator-controlled pause, with explicit MXC qualification before unattended work. The separate-identity instructions below describe the optional legacy `dedicated-runner` mode only. Neither mode activates the roadmap automatically.
|
||||
|
||||
This implementation builds the orchestrator only. **The real backlog is disabled. Phase 10 is NO-GO pending its own entry decision.** See [audit](AUDIT.md), [gate register](GATES.md), [security boundary](SECURITY.md), and [acceptance evidence](ACCEPTANCE.md).
|
||||
|
||||
## What is installed
|
||||
@@ -32,7 +34,7 @@ pwsh -NoProfile -File automation/tests/Test-Approvals.ps1 -Verifier "$PWD\script
|
||||
|
||||
Tests create disposable local worker repositories and bare remotes. The subprocess double exercises the real supervision/result/report paths without a model or network. RSA tests use temporary in-memory keys/certificates and do not install an owner key. They do not qualify the Windows sandbox or real application acceptance.
|
||||
|
||||
## Provision an actual runner, after approval
|
||||
## Optional legacy dedicated-runner provisioning
|
||||
|
||||
Use a dedicated development Windows account/VM with no production credentials, mounts, Docker socket, remote admin access or production network routes. Keep the owner's signing identity separate. A source worktree provides edit isolation; it is not a production security boundary. Prefer a **separate clone** for unattended execution, avoiding shared Git metadata/hooks with ongoing human work. The owner must protect main/production refs server-side and grant the publisher only the intended development refs.
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Controller trust boundaries
|
||||
|
||||
## Single-user-local update
|
||||
|
||||
`single-user-local` supports the same Windows SID for owner/controller. It uses a dedicated auth-only CODEX_HOME with a fresh sign-in to the same ChatGPT account; no tokens are copied. See [single-user operation](SINGLE_USER.md) and its [acceptance report](SINGLE_USER_ACCEPTANCE.md). The older separate-owner requirements below apply to `dedicated-runner`, not to initializing the single-user mode.
|
||||
|
||||
The single-user worker uses an explicit MXC named permission profile: filesystem root denied, minimal trusted tools readable, exact worker/temp paths writable, control/auth/normal-Codex roots denied, Git metadata read-only, known production environment paths denied, command network disabled. Apps, plugins, remote plugins, MCP servers and web search are explicitly disabled. Neither legacy fallback nor unrestricted execution is allowed. Real canary probes cover workspace read/write, seven denied file categories, a listening host-loopback socket and temporary certificate/CNG signing. The exact configured owner key additionally needs a positive host signing control and negative worker probes before unattended mode.
|
||||
|
||||
Same-account isolation protects against the confined worker, not against arbitrary unrestricted processes already running as the owner. Such processes can alter owner files or invoke owner credentials. This does not provide the independent administrative boundary of a separate runner identity. A stopped operator terminal, native restrictions, protected state and signed scope are all still required. Failure, incomplete proof, cleanup failure, changed policy or expired qualification retains operator-controlled pause; it never substitutes writable approval JSON.
|
||||
|
||||
## Threat model
|
||||
|
||||
Treat the worker model, repository content, test/build scripts, uploaded inputs and tool output as untrusted execution. Protect owner approvals, controller policy/code, durable state, test receipts, source identity, development publication and all production assets. Threats include forged PASS/approval JSON, replayed decisions, modified tests/artifacts, policy replacement, overlapping workers, branch/push manipulation, secret exposure and orphan processes.
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Run from your existing Windows and ChatGPT account
|
||||
|
||||
`single-user-local` removes the second Windows-account/VM requirement. It keeps the original queue, signed decisions, Git guards, recovery, locking and finite resource budgets. **Phase 10 and the actual roadmap remain disabled.** The current accepted development baseline is still an explicit policy decision, not something setup infers from main.
|
||||
|
||||
## Setup once
|
||||
|
||||
From the tooling worktree on `codex/autonomous-roadmap-single-user`:
|
||||
|
||||
```powershell
|
||||
pwsh -NoProfile -File .\scripts\Run-JobjaktBacklog.ps1 -Command setup
|
||||
. .\scripts\Use-JobjaktBacklog.ps1
|
||||
Jobjakt status
|
||||
Jobjakt dry-run
|
||||
```
|
||||
|
||||
Setup detects the current username/SID, Codex, Git, PowerShell, Python and this separate repository worktree. It installs at `$HOME\.jobjakt-backlog\single-user-local`, with an auth-only child directory and a separate task temp directory. This stable home-relative location avoids Codex desktop package LOCALAPPDATA redirection. Use `-Repository <isolated clone/worktree>` and `-ControlRoot <new location>` for explicit paths. A separate clone remains preferable for long-running development, but another Windows identity is unnecessary.
|
||||
|
||||
Existing state, prompts, activation policy and authentication are never reset by setup. A disabled, unused single-user installation may refresh the trusted code only; requalify after code changes. An existing dedicated installation remains separate and unchanged. No machine user, VM, paid service, signing key, scheduled task or token is created by basic setup. The optional `init` command retains the older dedicated-runner mode.
|
||||
|
||||
In later terminals, load the short command once:
|
||||
|
||||
```powershell
|
||||
. "$HOME\.jobjakt-backlog\single-user-local\Use-JobjaktBacklog.ps1"
|
||||
Jobjakt status
|
||||
```
|
||||
|
||||
This adds a function to that terminal only. It does not edit your normal PowerShell profile or Codex configuration. If you selected a custom ControlRoot, invoke its `Run-JobjaktBacklog.ps1` directly with `-Command`; it detects its own installed directory.
|
||||
|
||||
## Sign into the same ChatGPT account
|
||||
|
||||
Run this yourself in a real PowerShell terminal:
|
||||
|
||||
```powershell
|
||||
Jobjakt auth
|
||||
Jobjakt auth-status
|
||||
```
|
||||
|
||||
Choose the **same ChatGPT account you already use** in the browser login. This is a new local login session to the same service account, not a second subscription. Authentication is forced to ChatGPT with file storage in the dedicated CODEX_HOME. No API-key login, access-token piping or copying of `auth.json` is performed. `auth-status` reports the authentication kind without printing credentials; the controller cannot establish that two human-selected accounts are the same merely from a directory name. Actual successful sign-in remains a human step; it was not done by this implementation task.
|
||||
|
||||
Normal authentication/config reuse is deliberately not offered: the normal home may contain unrelated plugins, servers, rules and credentials. An auth-only home plus explicit capability restrictions avoids inheriting that configuration. Account quotas/rate limits remain those of your existing account; no new subscription or usage allowance is promised.
|
||||
|
||||
## Signing key and real qualification
|
||||
|
||||
These operator actions require your interactive terminal and no active controller worker:
|
||||
|
||||
```powershell
|
||||
Jobjakt key
|
||||
Jobjakt qualify
|
||||
```
|
||||
|
||||
`key` creates a nonexportable RSA owner certificate in **your current Windows user** certificate store, exports only its public certificate to ControlRoot, and pins its hash/thumbprint/SID. It does not replace an existing configured key. It grants no roadmap authority. The private key is never written to the repository or copied between accounts.
|
||||
|
||||
`qualify` launches only trusted synthetic probes through native MXC. It first proves canaries and keys are usable from the trusted operator context, then checks the worker cannot read/open for writing protected configuration, approvals, a signing-key file canary, normal Codex data, personal-file canaries, an unrelated-repository canary or synthetic production credentials. It tests denied socket access against a real listening loopback port and attempts certificate/CNG signatures with a temporary same-user key. When your actual owner key is configured, the exact pinned key also needs a host-positive and worker-negative signing test. No real production credential, personal document, external endpoint or model is used. Synthetic certificates/files are cleaned up; any cleanup failure blocks qualification.
|
||||
|
||||
Results are saved at `qualification.json`, including scope, binding, issue time and actual owner-key disposition. **A canary PASS alone is not unattended approval.** Missing owner key, incomplete/failed/stale probes or changed configuration keeps the controller paused. Qualification expires after 24 hours, and start rechecks native boundaries. The stock legacy sandbox's earlier CryptUnprotectData failure was not bypassed: this mode explicitly selects the [documented MXC implementation](https://learn.chatgpt.com/docs/windows/windows-sandbox) and refuses fallback. Its deny/read/write rules use the supported [permission-profile format](https://learn.chatgpt.com/docs/permissions).
|
||||
|
||||
After reviewing a successful qualification of your real key, you can select the runtime policy:
|
||||
|
||||
```powershell
|
||||
Jobjakt enable-unattended
|
||||
```
|
||||
|
||||
This requires your typed confirmation, but still does **not** enable the queue or authorize Phase 10. The enabled manifest, environment grant, roadmap grant and exact phase entry approvals remain independently signed through the existing `configure` workflow. Do not perform that activation until current Pre-Phase-10 acceptance and publication are finished and you explicitly approve Phase 10 entry.
|
||||
|
||||
If the native boundaries cannot be enforced, use the default `operator-controlled` policy. `start`/`resume` cannot launch autonomous workers under that policy. You can inspect status/logs/requests and use `prepare` to generate a protected inspection-only checkpoint brief. This is a deliberate execution pause, not an unsandboxed “interactive” fallback. Resolve the precise boundary or use an independently protected approval/execution mechanism before allowing untrusted automation.
|
||||
|
||||
## Routine commands
|
||||
|
||||
```powershell
|
||||
Jobjakt validate
|
||||
Jobjakt dry-run
|
||||
Jobjakt status
|
||||
Jobjakt current
|
||||
Jobjakt logs
|
||||
Jobjakt start # only after qualified runtime and separately signed phase activation
|
||||
Jobjakt pause
|
||||
Jobjakt resume
|
||||
Jobjakt retry -Stage PHASE-10
|
||||
Jobjakt recover
|
||||
Jobjakt approve
|
||||
```
|
||||
|
||||
`approve` shows the exact pending JSON request and requires a typed challenge, an explicit Approve/Revise/Reject disposition and your concrete decision text. It signs with the pinned owner key. It holds the repository lock and refuses active workers. A worker subprocess has no terminal input and cannot use the key when qualification is valid. A JSON file claiming approved remains invalid.
|
||||
|
||||
For homepage decisions, choose elements or revisions in the decision text. `Revise` reruns that checkpoint; final `Approve` advances after all gates pass. Product scope, provider rights, translation review, material security decisions and release evidence retain their gates. There is no automatic deployment or main merge path.
|
||||
|
||||
For an interrupted run: inspect the recorded process tree, run `recover` to create its exact request, run `approve` after confirming the tree is gone, then `recover` again and `resume`. Only the recovery request can be signed while recovery-required is set. A live recorded PID or an unverifiable PID marker still blocks signing. Never kill a reused PID blindly. Signing alone does not clear recovery-required. Publication failures reuse the exact verified local commit; no model rerun or force push is needed.
|
||||
|
||||
## Overnight and scheduling
|
||||
|
||||
The controller works without its GUI remaining open. A qualified run can continue with the desktop **locked**, provided the existing user session, dedicated authentication and signing provider are available and the PC is awake. No lock, sleep, firewall or elevation setting is changed. Logging out is different from locking: unattended execution before login requires you to configure the existing account's batch credentials/profile in Windows Task Scheduler and qualify that actual context. This implementation does not collect or store your Windows password.
|
||||
|
||||
Optional task definition, after real qualification:
|
||||
|
||||
```powershell
|
||||
pwsh -NoProfile -File .\scripts\Register-JobjaktBacklogTask.ps1
|
||||
# Review its preview, then explicitly register:
|
||||
pwsh -NoProfile -File .\scripts\Register-JobjaktBacklogTask.ps1 -Install
|
||||
```
|
||||
|
||||
It uses your existing login, limited privileges, logon plus 15-minute continuation, an eight-hour task limit and no overlapping instances. Scheduled continuation uses `start`, preserving a manual pause; `resume` is the owner's deliberate unpause. The registration script refuses unqualified runtime/key state. No task was registered by this work.
|
||||
|
||||
## Security difference and current handoff
|
||||
|
||||
Real canaries verify the tested native-worker boundaries. They are not an exhaustive proof against every Windows API, credential provider or future sandbox defect. Unrestricted applications running under your same Windows identity are outside the worker boundary and can still act as you. This is not equivalent to an independently administered account/VM. Apps, plugins, MCP and web search remain disabled in this mode; a later security scan/provider task needing them must pause for independently qualified capabilities, not silently enable your normal configuration.
|
||||
|
||||
At handoff: setup and canary qualification have been exercised under the current login; the dedicated home is **not signed in**, the real owner key is **not configured**, operation is **operator-controlled**, and the queue is **disabled**. See [acceptance and evidence](SINGLE_USER_ACCEPTANCE.md). Your next steps are the same-account `auth`, operator `key`, and real-key `qualify` commands; actual roadmap activation still waits for formal Phase 10 entry.
|
||||
@@ -0,0 +1,50 @@
|
||||
# AUTONOMOUS-ROADMAP-02 acceptance — 29 October 2026
|
||||
|
||||
**Single-user mode implemented and installed. Actual roadmap execution remains disabled. Phase 10: NO-GO without its separate formal entry approval.**
|
||||
|
||||
Source: `codex/autonomous-roadmap-single-user`, based on `c1663df`, in the existing isolated orchestrator worktree. The ongoing Pre-Phase-10 worktree was not edited, checked out, tested or operated. No main merge or production operation was performed.
|
||||
|
||||
## Decisions
|
||||
|
||||
| Area | Result | Evidence / boundary |
|
||||
|---|---|---|
|
||||
| Current Windows login setup | **PASS** | Setup detected the actual current SID for both owner/controller and installed outside the worker. No account, VM or subscription was created. Stable `$HOME/.jobjakt-backlog/single-user-local` location avoids desktop package path redirection. |
|
||||
| Same ChatGPT account support | **IMPLEMENTED; HUMAN SIGN-IN PENDING** | Dedicated auth-only CODEX_HOME, forced ChatGPT/file credentials and operator-terminal login. Existing tokens/config were not read/copied. The new profile is currently unsigned-in; actual identity, entitlement and inference are not claimed. |
|
||||
| Native filesystem boundaries | **PASS for real canaries** | Actual MXC process could read/write its workspace; all seven protected canary categories denied reads and write-handle opens. Files existed and were host-readable/writable before probing. No private documents/production secrets were used. |
|
||||
| Native command networking | **PASS for real loopback canary** | Host-positive listening TCP socket; worker connection denied under the same explicit network-disabled profile used for future sessions/checks. No production or third-party endpoint was contacted. This is finite evidence, not exhaustive network testing. |
|
||||
| Same-user signing protection | **CANARY PASS; REAL KEY NOT CONFIGURED** | Temporary nonexportable current-user key was usable by the host, inaccessible through worker certificate and direct CNG attempts, then cleaned up. The actual pinned owner key must pass its own host-positive/worker-negative tests before unattended mode. |
|
||||
| Apps/plugins/MCP | **PASS for compiled configuration** | Installed CLI reported apps, plugins and remote-plugin features false under the exact overrides; effective MCP server list was empty. Web search is explicitly disabled. No unrelated normal configuration is inherited by design; no model-backed tool session was run. |
|
||||
| Approval workflow | **PASS in tests; live owner action pending** | Signed verifier retained; typed challenge plus concrete disposition/decision; no active-worker signing; exact recovery request can be signed after reconciliation. Noninteractive approval and arbitrary writable approval JSON remain rejected. |
|
||||
| Regression | **PASS** | 69 distinct Python tests: all original 48 plus 21 single-user tests, zero failures/errors/skips in the final source-stable run. Six separate original .NET signature cases also pass; focused reruns are not added to those totals. |
|
||||
| Git/pause/recovery/concurrency | **PASS in disposable flows** | Single-user tests cover ordered publication, missing approval, pause/resume, publication-only retry, common-directory locking, interrupted-state guard and main protection. Original safety tests remain unchanged. |
|
||||
| Overnight/scheduling | **IMPLEMENTED; LIVE SCHEDULE NOT QUALIFIED** | Native Job controls retained, optional limited-user task script refuses unqualified state. No task was installed. No physical reboot/locked-desktop/logged-out run was performed. |
|
||||
| Unattended real roadmap | **BLOCKED / DISABLED** | Default operator-controlled policy, zero real sessions, no actual owner key, no ChatGPT sign-in, unconfigured application qualification adapter, and no Phase 10 authorization. No security control was bypassed to enable it. |
|
||||
|
||||
## Evidence
|
||||
|
||||
`automation/reports/single-user/` contains:
|
||||
|
||||
- `results.json` and `tests.txt`: final complete regression, distinct totals, before/after source-stability assertion and hashes.
|
||||
- `signature-results.json` and `signature-tests.txt`: six disjoint actual .NET signature-verifier cases.
|
||||
- `native-qualification.json`: actual MXC canary results, policy/source binding, issue time, cleanup status and explicit real-owner-key NOT_CONFIGURED scope.
|
||||
- `setup-results.json`: same Windows identity, empty dedicated authentication, zero sessions, disabled queue and Task Scheduler refusal before registration.
|
||||
- `capabilities.json`: actual CLI feature-state verification and zero effective MCP servers.
|
||||
- `format-check.json`: packaging removed one trailing space in the new test file after the full run; its Python AST is identical to the tested bytes. The original full-run hash remains recorded, with the packaged hash separately identified. No extra test count is added for formatting.
|
||||
|
||||
The first new MXC probe could not start because the old subprocess environment omitted SystemDrive. Only that non-secret OS variable was added to the existing allowlist; no unrestricted environment or sandbox fallback was enabled. Explicit MXC startup and the subsequent real canary probes passed. The previous legacy CryptUnprotectData result remains historical evidence; the user's normal saved sandbox selection was not changed.
|
||||
|
||||
The independent read-only review found two issues: the convenient approve command could not sign its own recovery request, and successful probe fields could override a BLOCKED qualification status. Both were reproduced with regression tests and fixed. Recovery still needs operator confirmation and a stopped/verifiably absent recorded process; signing alone never clears recovery-required. Qualification now requires PASS with no failure as well as complete probes, current binding, freshness and the real owner-key denial.
|
||||
|
||||
Setup from both source and the installed wrapper was exercised. Existing state/auth/policy is preserved. A packaging/setup correction makes the installed wrapper reuse its stored repository path rather than incorrectly require ControlRoot to be a Git checkout. This change was verified and included in the final regression source hashes.
|
||||
|
||||
## Restrictions retained
|
||||
|
||||
The original numbered prompt snapshots, order, dependencies, stage-specific owner gates, retry/session/time budgets, report/artifact verification and protected approval mechanism remain. Development completion is not production release. Failed publication keeps the exact tested commit; no force push, main merge, deployment, destructive migration, production credentials or live model activation is added.
|
||||
|
||||
Single-user confinement is not an independent administrator boundary. An unrestricted process already acting as the same Windows user can access owner files/credentials outside the worker sandbox. Tested canaries do not prove all Windows APIs, credential providers, future files or sandbox defects are harmless. An actual owner key, current sign-in and the qualified execution context are still required. A failed or incomplete boundary keeps the operator-controlled pause; it never launches an unconfined interactive worker.
|
||||
|
||||
The source still carries the intentional unconfigured provider/browser/Python/PDF/security/preservation adapter gate from AUTO-01. This task does not invent or waive application qualification. Actual roadmap activation must wait for finished Pre-Phase-10 acceptance, a published accepted baseline, explicit candidate/scope entry and the existing signed grants.
|
||||
|
||||
## Next owner actions
|
||||
|
||||
See [SINGLE_USER.md](SINGLE_USER.md) for exact commands. In your own terminal, load `Use-JobjaktBacklog.ps1`, run `Jobjakt auth` with your existing ChatGPT account, then `Jobjakt key` and `Jobjakt qualify` to test the actual key. Do not activate the queue yet. `Jobjakt status`, `dry-run`, `logs`, `pause`, `resume`, `retry`, `recover` and `approve` remain available through the short command; workers remain disabled until their independent runtime and phase gates are met.
|
||||
@@ -0,0 +1,11 @@
|
||||
# AUTONOMOUS-ROADMAP-02
|
||||
|
||||
Implement on `codex/autonomous-roadmap-single-user`, based on `c1663df`, in the existing isolated tooling worktree. No real roadmap, main merge or production operation.
|
||||
|
||||
- [x] Add `single-user-local` setup under the current Windows SID, a dedicated auth-only CODEX_HOME, and short PowerShell commands. Preserve the explicit disabled baseline. Never copy tokens or change the normal Codex configuration.
|
||||
- [x] Retain legacy dedicated-runner checks. In the new mode use an explicit MXC permission profile: deny filesystem root, allow minimal tools and the worker only, deny control/auth/normal Codex roots, keep command network off and plugins disabled. Apply the exact same profile to worker and test subprocesses.
|
||||
- [x] Implement real canary read/write, loopback network, and certificate/CNG signing probes. A successful startup alone is insufficient. Record failed/not-tested boundaries independently.
|
||||
- [x] Default to operator-controlled pause. Only a current successful qualification, protected signed approvals and explicit phase authorization can enable unattended operation. No writable approval-JSON fallback. Approval UI requires a real operator terminal and no active workers.
|
||||
- [x] Extend tests while retaining all existing tests. Verify disabled setup/dry-run, auth-home isolation, pause/recovery/locking/publication, and actual native sandbox canaries; publish truthful acceptance and usage.
|
||||
|
||||
Choice: the existing owner account and same ChatGPT account are supported; different accounts/VMs are optional, not setup prerequisites. Same-account approval is conditional on an inaccessible signing key and protected filesystem boundaries. If either fails, keep workers stopped and require operator action rather than claim equivalence to an independently administered runner.
|
||||
@@ -1,5 +1,7 @@
|
||||
# Autonomous roadmap follow-up
|
||||
|
||||
AUTONOMOUS-ROADMAP-02 adds the normal-login route in [SINGLE_USER.md](SINGLE_USER.md). Single-user setup and native canary qualification are implemented; the real owner key, same-account sign-in and Phase 10 authorization remain owner actions. The separate-account provisioning below is now optional; single-user MXC qualification is the alternative.
|
||||
|
||||
Implementation checkpoints AUTO-00–08 are complete in the qualified scope described in ACCEPTANCE.md. The following are deliberately **not authorized/completed** by installing the controller:
|
||||
|
||||
- [ ] Finish current Pre-Phase-10 acceptance; owner records final accepted baseline and candidate-specific cleanup entry.
|
||||
|
||||
Reference in New Issue
Block a user