Commit Graph

21 Commits

Author SHA1 Message Date
didericis efb3af4a93 feat(agent-provider): user plugin discovery, Dockerfile cascade, and provider-owned ca/git provisioning
- Add _load_user_plugin: loads AgentProvider subclass from
  ~/.bot-bottle/contrib/<name>/agent_provider.py; get_provider()
  checks there first before falling back to built-ins
- Add Dockerfile cascade to docker prepare: per-bottle override →
  manifest dockerfile → user plugin Dockerfile → provider default
- Move provision_ca and provision_git from backend-specific
  provision/ modules to AgentProvider ABC as overridable defaults;
  delete docker/provision/ca.py, docker/provision/git.py,
  smolmachines/provision/ca.py, smolmachines/provision/git.py
- Add git_gate_insteadof_host/scheme properties to BottlePlan base;
  SmolmachinesBottlePlan overrides them to return agent_git_gate_host
  and "http" so provision_git works correctly on both backends
- Move SIGKILL retry from smolmachines provision/ca.py into
  SmolmachinesBottle.exec via _exec_raw helper — all exec calls
  on smolmachines now transparently retry once on exit 137
- Relax manifest_agent template validation to allow user-defined
  template names; keep auth_token/forward_host_credentials guards
  for built-in-only features
- Update tests: rewrite test_docker_provision_git_user and
  test_smolmachines_provision to call provider methods directly;
  add TestSmolmachinesBottleExec for SIGKILL retry coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 11:35:35 -04:00
didericis-claude a59da9921e chore: remove all pipelock references from tests, docs, and non-pipelock source
lint / lint (push) Failing after 1m26s
test / unit (pull_request) Failing after 35s
test / integration (pull_request) Successful in 44s
- Strip pipelock from all unit and integration test fixtures:
  proxy_plan fields removed from DockerBottlePlan/SmolmachinesBottlePlan
  constructors; pipelock-specific test classes deleted or renamed
- Update test_sidecar_init: remove test_pipelock_loses_egress_tokens,
  rename "pipelock" daemon fixtures to "git-gate" throughout
- Remove test_pipelock_binary_present_and_versioned from integration test
- Remove test_pipelock_answers_on_bundle_ip from smolmachines launch test
- Update _SANDBOX_BLOCK_MARKERS: remove "pipelock" marker (egress blocks)
- Dockerfile.sidecars: remove pipelock build stage and COPY; update layout
  comments and port table
- egress_entrypoint.sh: update comments now that egress is sole proxy
- Clean up pipelock references in comments/docstrings across backend,
  network, manifest, supervise, git_gate, yaml_subset, agent_provider,
  sidecar_bundle, sidecar_init, egress_addon_core modules

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:54:06 +00:00
didericis-claude 83db7336c8 refactor(agent_provider): drop GUEST_HOME default, backend drives guest_home
Per PR review feedback (review #130): the GUEST_HOME = '/home/node'
default in agent_provider.py was driving the wrong direction —
the agent provider shouldn't ship its own opinion about the guest
home, the backend should.

- Removes the GUEST_HOME constant.
- Makes guest_home a required kwarg on AgentProvider.provision_plan
  and the agent_provision_plan shim (no default).
- Drops module-level _SKILLS_DIR / _PROMPT_PATH constants from
  contrib/{claude,codex}/agent_provider.py; both providers now
  derive the in-guest paths from plan.workspace_plan.guest_home
  at call time, which the backend's prepare step populated.
- Updates tests/unit/test_agent_provider.py callers to pass
  guest_home explicitly. The backend prepare paths already pass
  it; no production-code call sites changed.
2026-06-03 21:38:13 -04:00
didericis-claude bcdffc8400 refactor(contrib): inline provision steps per-provider, drop shared apply module
Each AgentProvider now owns its skills / prompt / provision /
supervise_mcp end-to-end. The base ABC declares all four as
abstract; ClaudeAgentProvider and CodexAgentProvider each carry
their own copy loop.

Per PR review feedback (review #128): the shared
_provision_apply.py abstraction was weak — Claude and Codex
harnesses already diverge (codex's dummy-auth + login-status
verify has no claude analogue) and forcing both onto one helper
just postpones the split. Duplication is intentional.

Deletes bot_bottle/_provision_apply.py and consolidates testing
under tests/unit/test_contrib_{claude,codex}_provider.py (one
file per provider, covering all four methods).
2026-06-03 21:38:13 -04:00
didericis-claude 44365ecf68 refactor(agent_provider): introduce AgentProvider ABC + contrib plugins
Lift the provider-specific blocks of agent_provision_plan into
contrib/claude/agent_provider.py and contrib/codex/agent_provider.py,
behind a new AgentProvider ABC and a lazy get_provider() registry
(mirrors PRD 0048's contrib convention).

agent_provision_plan and runtime_for stay as thin shims so existing
callers in backend/{docker,smolmachines}/prepare.py and cli/start.py
keep working without per-call edits — the shipping diff in this commit
is purely 'who owns the producer'.

Adds bot_bottle/_provision_apply.py — the backend-agnostic
skills / prompt / declarative-plan apply loops the per-provider
default methods will dispatch through in the next commit.
2026-06-03 21:38:13 -04:00
didericis-codex 6150497b47 feat(workspace): trust resolved project path 2026-06-02 16:57:52 +00:00
didericis-claude 0e29bcc829 refactor(egress): use provisioned_env instead of sentinel for Codex token (PRD 0030)
test / unit (pull_request) Successful in 39s
test / integration (pull_request) Successful in 45s
Add `provisioned_env: dict[str, str]` to `AgentProvisionPlan`. When
`forward_host_credentials=True`, `agent_provision_plan` reads the host
Codex access token at prepare time and stores it under
`CODEX_HOST_CREDENTIAL_TOKEN_REF`. Both backends merge `provisioned_env`
over `os.environ` before calling `egress_resolve_token_values`, so the
token slot resolves like any other manifest-declared token ref.

Removes `egress_resolve_token_values_with_provider` and the sentinel
`continue` skip from `egress_resolve_token_values`. The function is now
fully generic — it neither knows nor cares about provider identity.
2026-06-02 04:53:23 +00:00
didericis-codex 36e3443d2e fix(codex): defer workspace trust handling
test / unit (pull_request) Successful in 29s
test / integration (pull_request) Successful in 42s
test / unit (push) Successful in 30s
test / integration (push) Successful in 44s
2026-06-02 03:11:51 +00:00
didericis-codex d6ebd0d2eb fix(egress): skip token slots for unauth provider routes
test / unit (pull_request) Successful in 30s
test / integration (pull_request) Successful in 43s
2026-06-02 03:06:10 +00:00
didericis f768d3a853 fix(agent): move default claude env vars to the right location 2026-06-01 22:24:17 -04:00
didericis-claude f32b7eb299 fix(agent): always emit passthrough egress route for api.anthropic.com
Mirrors the Codex pattern: Claude always gets a tls_passthrough route
for api.anthropic.com so user-set tokens aren't stripped by pipelock,
whether or not auth_token is declared. Auth injection (scheme + token_ref)
and the placeholder env only apply when auth_token is set.

Assisted-by: Claude Code
2026-06-01 22:24:17 -04:00
didericis-claude de9bd7eb83 feat(manifest): add agent_provider.auth_token for Claude OAuth via egress
Operators can now declare:

  agent_provider:
    template: claude
    auth_token: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN

and the provisioner injects a provider-owned api.anthropic.com egress
route (Bearer, tls_passthrough) rather than requiring a manually
declared route with the former claude_code_oauth role.

Changes:
- Add auth_token field to AgentProvider; validate claude-only.
- Remove claude_code_oauth from EGRESS_ROLES / PROVIDER_EGRESS_ROLES.
  Manifests that declare the role now fail at parse time with "unknown
  role" — the provisioner owns the route.
- agent_provision_plan: replace manifest_egress_routes/has_provider_auth
  with auth_token; Claude branch injects the api.anthropic.com route,
  placeholder env, and nonessential-traffic flags when auth_token is set.
- Add hidden_env_names: frozenset[str] to AgentProvisionPlan; Claude
  branch populates it with CLAUDE_CODE_OAUTH_TOKEN.
- Remove auth_role from AgentProviderRuntime and placeholder_env_for().
- print_util.visible_agent_env_names: accept hidden_env_names from the
  plan instead of dispatching on agent_provider_template.
- Both backends: drop manifest_egress_routes call, pass auth_token.
- PRD 0029 rescoped to cover both Codex and Claude provider auth.

Assisted-by: Claude Code
2026-06-01 22:24:17 -04:00
didericis-claude 952dcd7eec refactor(agent): move placeholder env injection into agent_provision_plan
The has_provider_auth check and egress-placeholder injection were
duplicated in both backends. Move them into agent_provision_plan so
the provisioner owns that decision entirely:

- Replace has_provider_auth: bool param with manifest_egress_routes,
  compute has_provider_auth internally from the route roles.
- Inject CLAUDE_CODE_OAUTH_TOKEN=egress-placeholder inside the plan
  when has_provider_auth, alongside the existing nonessential-traffic
  vars. Backends no longer touch the placeholder env.
- Remove placeholder_env from AgentProviderRuntime; expose
  placeholder_env_for() for print_util's hide-from-summary logic.

Assisted-by: Claude Code
2026-06-01 22:24:17 -04:00
didericis-claude 59df0b0f0f fix(codex): emit passthrough egress routes when not forwarding host credentials
When forward_host_credentials is false, Codex bottles should still get
tls_passthrough routes for the OpenAI/ChatGPT hosts so that tokens a
user sets via `codex login` after launch aren't stripped by pipelock's
header DLP. Previously no routes were emitted, which would have blocked
those requests entirely once pipelock enforcement tightens.

Rename the test to reflect the new expected behavior.

Assisted-by: Claude Code
2026-06-01 22:24:17 -04:00
didericis-claude 884cedc160 refactor: provision egress routes via AgentProvisionPlan
Remove provider-specific branching from egress.py and pipelock.py.
Previously, `egress_routes_for_bottle` and `pipelock_effective_tls_passthrough`
both contained `template == "codex"` checks — the same pattern the rest
of the PR moved out of the backends.

Root cause: `EgressRoute` had no `tls_passthrough` field, so pipelock
couldn't learn from the synthesised Codex routes that they needed
passthrough. Fix:

- Add `EgressRoute.tls_passthrough: bool`. `egress_manifest_routes` lifts
  the existing `pipelock.tls_passthrough` manifest flag here; provider
  routes set it directly.
- Add `AgentProvisionPlan.egress_routes`. `agent_provision_plan` populates
  it for Codex + `forward_host_credentials`, including `tls_passthrough=True`.
- Replace Codex-specific `egress_routes_for_bottle` logic with a generic
  `_merge_provider_route` helper. Backends call `egress_routes_for_bottle(bottle,
  plan.egress_routes)`; no provider type checks inside egress or pipelock.
- Rewrite `pipelock_effective_tls_passthrough` to read `route.tls_passthrough`
  from the merged route set instead of re-implementing the provider check.
- Both backends now call `agent_provision_plan` before `Egress.prepare` and
  `PipelockProxy.prepare`, threading `plan.egress_routes` to both. `has_provider_auth`
  is derived from `egress_manifest_routes` (manifest routes only — provider
  routes carry no auth roles, so the result is identical).

Assisted-by: Claude Code
2026-06-01 22:24:17 -04:00
didericis-codex 76a7921ae6 refactor(agent): move claude env defaults into plan 2026-06-01 22:24:17 -04:00
didericis-codex c8ab0c67a8 refactor(agent): surface provider env defaults 2026-06-01 22:24:17 -04:00
didericis-codex e808e81b87 refactor(agent): group provider provisioning into plan 2026-06-01 22:24:17 -04:00
didericis-codex cea832b21d fix(codex): stop injecting api key placeholder
test / unit (pull_request) Successful in 27s
test / integration (pull_request) Successful in 41s
2026-05-29 02:39:37 -04:00
didericis-codex 1cbedc91c0 refactor(agent): use agent-neutral runtime names
Assisted-by: Codex
2026-05-28 17:59:24 -04:00
didericis-codex c08b09dc9f refactor!: rename project to bot-bottle
Assisted-by: Codex
2026-05-28 17:56:14 -04:00