feat(fleet-deploy): log-tail contract as a Score companion #295
Open
johnride
wants to merge 2 commits from
feat/v0-3-logs-companion into feat/smoke-test-contract
pull from: feat/v0-3-logs-companion
merge into: NationTech:feat/smoke-test-contract
NationTech:master
NationTech:feat/fleet-ch2-operator-recovery
NationTech:feat/fleet-device-exec-logs
NationTech:feat/zitadel-web-pkce-and-human-user
NationTech:feat/jwt-bearer-openbao-auth
NationTech:feat/fleet-ch5-graceful-deploy-upgrade
NationTech:feat/fleet-ch4-agent-upgrade
NationTech:feat/fleet-ch3-log-streaming
NationTech:feat/add-claims-for-openbao
NationTech:refactor/move-zitadel-jwt-to-module
NationTech:feat/fleet-operator-real-data
NationTech:docs/fleet-secrets-device-access
NationTech:chore/fleet-operator-prune-mock-dtos
NationTech:chore/rename-release-to-publish
NationTech:refactor/config-namespace-env-var
NationTech:feat/fleet-staging-openbao
NationTech:feat/auth-add-next-url-redirect
NationTech:pr/harmony-sso-example
NationTech:feat/unified-config-and-secrets
NationTech:ci/fleet-argo-cd
NationTech:ci/fleet-operator-release-pipeline
NationTech:feat/on-device-key-gen
NationTech:feat/install-gitea
NationTech:refactor/smoke-companion-minimal
NationTech:feat/smoke-test-contract
NationTech:feat/iobench-redpanda-profile
NationTech:feat/v0-3-dashboard-role-enforcement
NationTech:feat/v0-3-init-containers
NationTech:feat/v0-3-operator-restart-baseline
NationTech:feat/fleet-e2e-x86
NationTech:feat/ceph-score
NationTech:feat/opnsense-bootstrap-score
NationTech:feat/fleet-e2e
NationTech:feat/fleet-e2e-harness-and-ping
NationTech:feat/dashboard-auth
NationTech:feat/fleet-operator-web-frontend
NationTech:feat/deploy_fleet_server_side
NationTech:feat/openwebui
NationTech:feat/iot-aggregation-scale
NationTech:feat/iot-operator-helm-chart
NationTech:feat/removesideeffect
NationTech:feat/test-alert-receivers-sttest
NationTech:feat/brocade-client-add-vlans
NationTech:feat/agent-desired-state
NationTech:feat/opnsense-dns-implementation
NationTech:feat/named-config-instances
NationTech:worktree-bridge-cse_012j1jB37XfjXvDGHUjHrKSj
NationTech:chore/leftover-adr
NationTech:feat/config_e2e_zitadel_openbao
NationTech:example/vllm
NationTech:feat/config_sqlite
NationTech:chore/roadmap
NationTech:feature/kvm-module
NationTech:feat/rustfs
NationTech:feat/harmony_assets
NationTech:feat/brocade_assisted_setup
NationTech:feat/cluster_alerting_score
NationTech:e2e-tests-multicluster
NationTech:fix/refactor_alert_receivers
NationTech:feat/change-node-readiness-strategy
NationTech:feat/zitadel
NationTech:feat/improve-inventory-discovery
NationTech:fix/monitoring_abstractions_openshift
NationTech:feat/nats-jetstream
NationTech:adr-nats-creds
NationTech:feat/st_test
NationTech:feat/dockerAutoinstall
NationTech:chore/cleanup_hacluster
NationTech:doc/cert-management
NationTech:feat/certificate_management
NationTech:adr/017-staleness-failover
NationTech:fix/nats_non_root
NationTech:feat/rebuild_inventory
NationTech:fix/opnsense_update
NationTech:feat/unshedulable_control_planes
NationTech:feat/worker_okd_install
NationTech:doc-and-braindump
NationTech:fix/pxe_install
NationTech:switch-client
NationTech:okd_enable_user_workload_monitoring
NationTech:configure-switch
NationTech:fix/clippy
NationTech:feat/gen-ca-cert
NationTech:feat/okd_default_ingress_class
NationTech:fix/add_routes_to_domain
NationTech:secrets-prompt-editor
NationTech:feat/multisiteApplication
NationTech:feat/ceph-install-score
NationTech:feat/ceph-osd-score
NationTech:feat/ceph_validate_health
NationTech:better-indicatif-progress-grouped
NationTech:feat/crd-alertmanager-configs
NationTech:better-cli
NationTech:opnsense_upgrade
NationTech:feat/monitoring-application-feature
NationTech:dev/postgres
NationTech:feat/cd/localdeploymentdemo
NationTech:feat/webhook_receiver
NationTech:feat/kube-prometheus
NationTech:feat/init_k8s_tenant
NationTech:feat/discord-webhook-receiver
NationTech:feat/kube-prometheus-monitor
NationTech:feat/tenantScore
NationTech:feat/teams-integration
NationTech:feat/slack-notifs
NationTech:monitoring
NationTech:runtime-profiles
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
No description provided.
Delete Branch "feat/v0-3-logs-companion"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Third Score companion (after AgentObservation and SmokeTest), per
ADR-023 P7 — new framework capabilities attach as companions rather
than as additions to the Score / Interpret public API. Powers the
dashboard's "View logs" UX: customer clicks the button, gets the last
N lines of a deployment's container output from the device.
Trait + transport-side impl + unit tests ship now. The agent-side
Verb::Logs handler and the operator dashboard handler land in
follow-up PRs against the contract locked here — splitting keeps each
diff focused and reviewable.
Three small types + a NATS-backed impl, zero edits to Score /
Interpret / Maestro:
LogChunk pure value: source identifier, captured_at, lines
(oldest-first), truncated flag. No transport,
no async, no IO — the dashboard renders it,
the transport layer constructs it.
LogQueryError six arms, each mapped to a distinct operator
action (DeviceOffline vs Timeout vs Agent vs
BadReply vs Transport vs InvalidReply). Mirrors
the FleetCommandsClient::CommandError shape used
by Verb::Ping so callers see uniform error
surfaces across verbs.
LogQuery companion trait paired with a Score by associated
type — Q: LogQuery<T, Score = S> is the same
compile-time lock SmokeTest uses. A future
K8sLogQuery follows the same shape, no
Box needed (topologies are
compile-time per ADR-023 P6).
PodmanLogQuery NATS request/reply impl targeting
device-commands..logs. Splits routing
(LogQueryRouting) from transport so unit tests
verify the exact wire bytes without a NATS
client. Saturates LogsRequest.lines at
LOGS_MAX_LINES on the operator side as
defense-in-depth (the agent will clamp again).
reconciler-contracts gains Verb::Logs, LogsRequest, LogsReply, and
the LOGS_MAX_LINES bound. The wire shape lives there (not in the
deploy crate) so the agent build — which must not depend on harmony
— can serialize the same bytes. Adding the verb required zero
permission template changes: the agent's existing
device-commands..> subscription already covers it, and the
verb stays the trailing subject token so Verb::as_subject_token
keeps its invariant.
Tests assert behavior, not shape: subject_matches_documented_format
locks the wire so a callout permission change can't silently break
routing, request_body_clamps_oversized_n proves the
buggy-dashboard-show-all-button can't get through unchecked,
decode_reply_rejects_invalid_source_name proves a malicious agent
can't smuggle control characters past ProbeName validation, and
paired_score_type_is_podman_v0_score is a compile-time check that
catches refactors changing the associated type without updating
callers. 77 unit tests total across both crates, all passing without
requiring a real podman socket or NATS server.
Deferred (in scope of v0.3, separate PRs):
LogsRequest, resolves deployment->container with stricter
[a-zA-Z0-9_.-]{1,128} validation, runs podman logs --tail,
serializes LogsReply).
/deployments//devices//logs.
Third Score companion (after AgentObservation and SmokeTest), per ADR-023 P7 — new framework capabilities attach as companions rather than as additions to the Score / Interpret public API. Powers the dashboard's "View logs" UX: customer clicks the button, gets the last N lines of a deployment's container output from the device. Trait + transport-side impl + unit tests ship now. The agent-side Verb::Logs handler and the operator dashboard handler land in follow-up PRs against the contract locked here — splitting keeps each diff focused and reviewable. Three small types + a NATS-backed impl, zero edits to Score / Interpret / Maestro: LogChunk pure value: source identifier, captured_at, lines (oldest-first), truncated flag. No transport, no async, no IO — the dashboard renders it, the transport layer constructs it. LogQueryError six arms, each mapped to a distinct operator action (DeviceOffline vs Timeout vs Agent vs BadReply vs Transport vs InvalidReply). Mirrors the FleetCommandsClient::CommandError shape used by Verb::Ping so callers see uniform error surfaces across verbs. LogQuery<T> companion trait paired with a Score by associated type — Q: LogQuery<T, Score = S> is the same compile-time lock SmokeTest uses. A future K8sLogQuery follows the same shape, no Box<dyn LogQuery> needed (topologies are compile-time per ADR-023 P6). PodmanLogQuery NATS request/reply impl targeting device-commands.<id>.logs. Splits routing (LogQueryRouting) from transport so unit tests verify the exact wire bytes without a NATS client. Saturates LogsRequest.lines at LOGS_MAX_LINES on the operator side as defense-in-depth (the agent will clamp again). reconciler-contracts gains Verb::Logs, LogsRequest, LogsReply, and the LOGS_MAX_LINES bound. The wire shape lives there (not in the deploy crate) so the agent build — which must not depend on harmony — can serialize the same bytes. Adding the verb required zero permission template changes: the agent's existing device-commands.<id>.> subscription already covers it, and the verb stays the trailing subject token so Verb::as_subject_token keeps its invariant. Tests assert behavior, not shape: subject_matches_documented_format locks the wire so a callout permission change can't silently break routing, request_body_clamps_oversized_n proves the buggy-dashboard-show-all-button can't get through unchecked, decode_reply_rejects_invalid_source_name proves a malicious agent can't smuggle control characters past ProbeName validation, and paired_score_type_is_podman_v0_score is a compile-time check that catches refactors changing the associated type without updating callers. 77 unit tests total across both crates, all passing without requiring a real podman socket or NATS server. Deferred (in scope of v0.3, separate PRs): - Agent-side Verb::Logs handler in command_server.rs (parses LogsRequest, resolves deployment->container with stricter [a-zA-Z0-9_.-]{1,128} validation, runs podman logs --tail, serializes LogsReply). - Operator dashboard handler at /deployments/<name>/devices/<id>/logs. - End-to-end integration test through a real podman container.cb83a1edfeto0793e72a05View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.