Tests / Test passed: 581
Host Agent: - One-time local operator account bootstrap (PBKDF2-HMAC-SHA256, atomic 0600-permission write) gating the daemon's first unattended start via a new `setup` CLI subcommand. - Default control-plane URL now https://amcp.home.jerryyan.top (env var override unchanged). - Enrollment no longer requires a pre-issued token; falls back to zero-token self-service enrollment when none is configured. Cloud control plane: - CLOUD_SELF_SERVICE_ENROLLMENT_ENABLED (default false) opt-in flag. - SelfServiceEnrollmentAuthProvider + ChainedEnrollmentAuthProvider: configured tokens still take priority; self-service only applies when no token matches, preserving edge-host-enrollment's token-bound path. - Fixed a latent bug in sql_repository.py::enroll_host: the token-conflict lookup used `== enrollment_token_digest`, which SQLAlchemy compiles to `IS NULL` when the value is None, so every self-service enrollment after the first would have falsely collided with an existing NULL-digest host. Skipped that lookup entirely when the digest is None. Docs/deploy: .env.example, compose.yaml, compose.deploy.yaml, CLOUD_DEPLOYMENT.md, MACOS_IPHONE_SETUP.md updated for the new flag, URL default, and required `device-host-agent setup` step. Verification: 494 non-integration tests pass; openspec validate --strict passes. PostgreSQL-backed contract tests and full manual end-to-end verification were not run (no Postgres/Docker or reachable cloud-api in this environment); noted as unchecked in tasks.md 7.2/7.4.
32 lines
912 B
Python
32 lines
912 B
Python
from __future__ import annotations
|
|
|
|
from dataclasses import replace
|
|
|
|
from host_agent.client import HostAgentEnrollmentClient
|
|
from host_agent.config import HostAgentConfig
|
|
from host_agent.identity import HostIdentityStore
|
|
|
|
|
|
def resolve_host_identity(
|
|
config: HostAgentConfig,
|
|
*,
|
|
identity_store: HostIdentityStore,
|
|
client: HostAgentEnrollmentClient,
|
|
) -> HostAgentConfig:
|
|
if config.host_id and config.token:
|
|
return config
|
|
state = identity_store.load_or_create()
|
|
if state.host_id is None:
|
|
response = client.enroll_host(
|
|
agent_instance_id=state.agent_instance_id,
|
|
host_token=state.token,
|
|
display_name=config.display_name,
|
|
)
|
|
state = identity_store.complete(state, response.host_id)
|
|
return replace(
|
|
config,
|
|
host_id=state.host_id or "",
|
|
token=state.token,
|
|
enrollment_managed=True,
|
|
)
|