Files
qinglong/deploy/console/ql3-cluster-copilot

Cluster read-only field Console

This Console is an operator-workstation process, not a resident QingLong service. Native execution serves digest-bound assets on an ephemeral 127.0.0.1 port and forwards only a fixed vocabulary of Run, Task, Workflow and Copilot reads to existing Cluster APIs. It never accepts a browser-provided URL or method. Do not deploy it as a Kubernetes workload, Ingress, shared LAN listener, Edge component or legacy 2.x Web route.

Run cancellation availability is a second, explicit authority. It is disabled by default. Supplying a separate Run management mTLS config and short-lived User assertion adds only status, blocked-list and inspect reads to the same loopback process; rearm, stop and retry remain absent.

Worker observation is a third, independent authority and is also disabled by default. Supplying its generic Worker management mTLS config and short-lived User assertion adds only a fixed 16-item list and point inspect to the same loopback process. Credential mutation, drain, revoke, background polling and automatic pagination remain absent.

Use ql3-cluster-admin from the same independently verified Admin release as the Cluster deployment. D-328 also supports the image-carried docker-loopback.sh: it uses an explicit container-only listener but publishes the same port exclusively on host 127.0.0.1. Arbitrary 0.0.0.0, host networking and LAN publication remain forbidden.

Verify the distribution

The multi-architecture qinglong3-cluster-admin@sha256:… OCI image is the distribution artifact. It already carries the exact launcher, examples and this document under /opt/qinglong/share/ql3-copilot-console/; there is no second Node archive or package dependency graph to trust.

From the exact reviewed source tag, run verify-release.sh with the immutable image digest, repository, 40-hex source revision and full tag ref. The verifier requires cosign and authenticated gh, then independently checks the keyless release-workflow identity, SLSA provenance, CycloneDX SBOM and digest-bound OS vulnerability evidence. It rejects tags and mutable image references.

deploy/console/ql3-cluster-copilot/verify-release.sh \
  ghcr.io/replace-owner/qinglong3-cluster-admin@sha256:REPLACE_64_HEX \
  replace-owner/qinglong \
  REPLACE_40_HEX_SOURCE_REVISION \
  refs/tags/v3.0.0-alpha.0

For a release acceptance ceremony, prefer the source-tag workstation runner. Create a current-owner 0700 report directory and a canonical 0600 file containing only a short-lived GitHub token. Pass canonical absolute executable paths (resolve Homebrew symlinks first). The token is sent only to the four gh attestation verify children, never in argv, the report or the cosign and docker environments.

node scripts/ql3-cluster-admin-release-workstation-ceremony.cjs \
  --image=ghcr.io/replace-owner/qinglong3-cluster-admin@sha256:REPLACE_64_HEX \
  --repository=replace-owner/qinglong \
  --source-revision=REPLACE_40_HEX_SOURCE_REVISION \
  --source-ref=refs/tags/v3.0.0-alpha.0 \
  --cosign=/canonical/absolute/cosign \
  --gh=/canonical/absolute/gh \
  --docker=/canonical/absolute/docker \
  --github-token-file=/absolute/private/release/github-token \
  --output=/absolute/private/release/admin-ceremony.json

In addition to the signature, provenance, CycloneDX, OS-vulnerability and source-derived release-candidate contract checks, the runner pulls the same immutable digest, confirms its local RepoDigests binding, and runs the image-carried evidence-verify command on a fixed non-sensitive vector with network disabled, a read-only root, no capabilities, no-new-privileges, 128 MiB, 0.25 CPU and 32 PIDs. It writes one new 0600 low-sensitive report and will not replace an existing file.

Audit that report independently against the expected public release identity:

node scripts/ql3-cluster-admin-release-workstation-ceremony-audit.cjs \
  --report=/absolute/private/release/admin-ceremony.json \
  --image=ghcr.io/replace-owner/qinglong3-cluster-admin@sha256:REPLACE_64_HEX \
  --repository=replace-owner/qinglong \
  --source-revision=REPLACE_40_HEX_SOURCE_REVISION \
  --source-ref=refs/tags/v3.0.0-alpha.0

The offline audit verifies canonical encoding, exact structure, tool and transcript digests, isolation claims and expected release binding. It does not replay registry or transparency-log queries and cannot turn the unsigned local report into an attestation or action authority. Keep the report private even though it contains no credential or workstation identity.

After verification, pull that exact digest. The signature covers the embedded host launcher and templates as part of the image filesystem. Operators may either use the launcher from the matching reviewed tag or extract its exact image-carried copy with docker create plus docker cp before execution.

Prepare private authority

Create an absolute canonical directory with mode 0700. For native execution it is owned by the current operator; for the image-carried launcher it and all files are owned by UID/GID 10001:10001. Copy client-config.example.json to client.json, install the reviewed Cluster API CA as ca.pem, and install a separately issued ql3c_ Project API credential as credential. Give the credential only run.read, task.read and artifact.read; run.read covers Run and Workflow observations, while task.read covers Task list/detail and artifact.read covers an explicitly requested Copilot output. The Console has no route for Run/Workflow start, diagnosis creation or cancellation even if a wider credential is supplied.

To enable the optional cancellation drill-down, copy run-management-client-config.example.json to run-management-client.json, install its CA, client certificate and private key, and issue a short-lived strong User assertion with only run.read into run-management-assertion.jwt. These files are independent of the Project API credential. Supplying only one of config/assertion is rejected before a listener or Cluster request is created. The assertion is reread for every explicit click so it can be rotated or removed while the Console is running.

To enable Worker observation, copy worker-management-client-config.example.json to worker-management-client.json, install its separate CA, client certificate and private key, and issue a short-lived strong User assertion with only worker.manage into worker-management-assertion.jwt. Its endpoint must be the D-374 canonical /api/v3/workers/management; the Console cannot accept the legacy credential-management path or a credential mutation command file.

To enable Plugin Package installation observation, copy package-management-client-config.example.json to package-management-client.json, install its CA, and issue a short-lived strong User assertion with only package.manage into package-management-assertion.jwt. Its endpoint is fixed to the canonical /api/v3/plugin-packages/management. This authority is independent of the Project, Run and Worker files; the Console exposes no Package command file or lifecycle mutation.

Create an independent 256-bit browser session key without placing its value in argv or an environment variable:

install -d -m 0700 /absolute/private/ql3-copilot-console
umask 077
node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))' > /absolute/private/ql3-copilot-console/session
chmod 0600 /absolute/private/ql3-copilot-console/client.json /absolute/private/ql3-copilot-console/ca.pem /absolute/private/ql3-copilot-console/credential /absolute/private/ql3-copilot-console/session

If optional Run management reads are enabled, apply the same owner-private, canonical, non-symlink 0600 rule to run-management-client.json, run-management-ca.pem, run-management-client.crt, run-management-client.key and run-management-assertion.jwt. Apply the same rule to worker-management-client.json, worker-management-ca.pem, worker-management-client.crt, worker-management-client.key and worker-management-assertion.jwt when Worker observation is enabled. Apply the same rule to package-management-client.json, package-management-ca.pem and package-management-assertion.jwt when Package observation is enabled.

Every file must be a current-owner, non-symlink, canonical regular file. The session file contains exactly 43 base64url characters and no newline. It is a browser-to-loopback secret only; it cannot authenticate to the Cluster API. The ql3c_ credential remains in the BFF process and is reread for every upstream request so file rotation takes effect without browser disclosure.

Check and start

Run the preflight first:

ql3-cluster-admin copilot-console --check \
  --config /absolute/private/ql3-copilot-console/client.json \
  --credential /absolute/private/ql3-copilot-console/credential \
  --session /absolute/private/ql3-copilot-console/session

Append both flags to preflight and serve when the optional authority is intended:

--run-management-config /absolute/private/ql3-copilot-console/run-management-client.json \
--run-management-assertion /absolute/private/ql3-copilot-console/run-management-assertion.jwt

Worker observation uses its own pair:

--worker-management-config /absolute/private/ql3-copilot-console/worker-management-client.json \
--worker-management-assertion /absolute/private/ql3-copilot-console/worker-management-assertion.jwt

Package observation also uses an independent pair:

--package-management-config /absolute/private/ql3-copilot-console/package-management-client.json \
--package-management-assertion /absolute/private/ql3-copilot-console/package-management-assertion.jwt

It validates every configured private authority and performs one unauthenticated TLS 1.3 GET /readyz. It does not open the Console listener or reveal paths, endpoint, credential, Project or Cluster identity.

Start a session with an ephemeral port:

ql3-cluster-admin copilot-console \
  --config /absolute/private/ql3-copilot-console/client.json \
  --credential /absolute/private/ql3-copilot-console/credential \
  --session /absolute/private/ql3-copilot-console/session \
  --port=0

Open only the exact http://127.0.0.1:<port> origin printed by the process, then enter the session key from the private file. The browser keeps it only in page memory; reloading locks the page. Stop the process with SIGINT or SIGTERM, then remove or rotate the session file.

The BFF accepts at most two concurrent reads and sixteen connections, rejects a third request without queueing, caps request bodies at 4 KiB and responses at approximately 2 MiB, disables cache/cookies/frames/workers, and never polls. Model text is rendered as plain text and remains untrusted advice. These limits keep the workstation surface bounded, but this Cluster-only product is still excluded from small router Edge/Standalone artifacts.

The default page exposes thirteen exact operations: Copilot inspect|output; Run list/detail/events/steps; Task list/detail; and Workflow list plus Workflow Run list/detail/events/steps. List responses use 32-row pages and offer an explicit next-page read only when the upstream cursor says more data exists. There is no automatic cascade from a list to details, steps or events, so each authority read remains visible and intentional.

Explicit Run management authority raises the available vocabulary to sixteen: one Project cancellation status, one fixed 16-item blocked snapshot page and one low-sensitive Run cancellation inspection. An attention_required status offers a user-clicked blocked-list step; each returned Run offers a user-clicked inspect step. Pagination is also click-only. There is no polling, automatic page traversal, bulk inspection or mutation route.

Explicit Worker management authority adds worker_list|worker_inspect. The list is fixed at 16 items and exposes a next cursor only as a new user-clicked read; each listed Worker can be inspected only by another explicit click. The projection contains bounded lifecycle, compatibility, architecture, protocol and capacity facts, but no credential, raw capability, label or Secret.

Explicit Package management authority adds package_list|package_inspect, for a maximum vocabulary of twenty operations when every optional authority is enabled. The list is fixed at 16 installations with click-only pagination and click-only inspection. The product projection includes Package version, installation state, availability and bounded recovery codes, but omits installation IDs, locks, record digests, transport identity and every Package mutation. Package authority remains disabled by default.

Export a redacted evidence bundle

After at least one successful read, Export redacted bundle creates one UTF-8 JSON file entirely in browser memory. Export performs zero BFF or Cluster requests and includes only the evidence already visible in the current page. The ledger retains at most the newest sixteen entries and 8 MiB of canonical raw facts; reaching either limit removes the oldest visible and in-memory entry. The generated file is capped at 512 KiB.

The fixed allowlist keeps operation, local observation time, reviewed status enums, bounded numeric/boolean facts, pagination state and typed aliases. Project, Run, Task, Workflow, Package, Step, Artifact, request and digest values become per-bundle aliases without an exported mapping. Free text, names, paths/URLs, commands, inputs/outputs, environment, errors/messages, credentials, tokens, authorization, unknown fields and Copilot model text are omitted. A canonical SHA-256 for each omitted raw fact allows a later local comparison without embedding that fact.

The top-level SHA-256 detects changes to the redacted JSON, but it is not a server signature, durable audit, origin attestation or action authority. Review the file before sharing it. Generation uses no upload, clipboard/share API, browser storage, worker, timer or service-side temporary file. Clear page removes the current in-memory ledger without sending a request.

Verify the downloaded file independently with the same reviewed Admin release:

ql3-cluster-admin evidence-verify \
  --bundle=/absolute/qinglong-cluster-evidence.json

The verifier performs one offline read-only file read, rejects noncanonical JSON and structural/redaction/typed-alias drift, and independently recomputes the bundle digest. Its output deliberately says that raw fact digests were not recomputed because those sensitive facts are absent; it does not claim a server signature, attestation, durable audit or action authority. The command does not upload, mutate or write the bundle.

Run the verified image

Create a dedicated Docker network whose egress is restricted by the host firewall to DNS and the exact Cluster API destination. Copy host-environment.example.json values into the launcher environment, replacing the image with the verified digest and selecting one unused host port. The launcher rejects bridge|default|host|none, mutable tags, noncanonical private roots, ports outside 1024..65535 and unknown resource classes.

The image launcher keeps Run management disabled unless QL3_COPILOT_CONSOLE_RUN_MANAGEMENT=enabled is set. Enabled mode reads run-management-client.json and run-management-assertion.jwt from the same read-only private mount; all certificate paths in the config must point into that mount. disabled is the only default and unknown values fail closed. Worker observation follows the independent QL3_COPILOT_CONSOLE_WORKER_MANAGEMENT=enabled switch and reads only its Worker config/assertion pair. Package observation follows QL3_COPILOT_CONSOLE_PACKAGE_MANAGEMENT=enabled and reads only its Package config/assertion pair. Enabling one management authority does not enable either of the others.

Resource class Memory CPU PIDs Console reads
compact 192 MiB 0.25 32 2, no queue
standard 512 MiB 1 64 2, no queue

Validate private authority and the upstream unauthenticated TLS 1.3 readiness route without opening or publishing a listener:

deploy/console/ql3-cluster-copilot/docker-loopback.sh check

Then start the foreground session:

deploy/console/ql3-cluster-copilot/docker-loopback.sh serve

The launcher fixes non-root UID, read-only root, no capabilities, no-new-privileges, bounded memory/CPU/PIDs, an 8 MiB noexec tmpfs, one read-only private mount and --pull never. serve alone adds --publish 127.0.0.1:<port>:<port>/tcp; check publishes nothing. The container listener is reachable only through this reviewed publication and continues to require the 256-bit browser session token plus exact Host/Origin.