Skip to content

klaus-gateway-test drives the Slack adapter; the web channel is gone #252

Description

@teemow

Problem

agentlab klaus-gateway-test drives klaus-gateway's web channel (GET /web/agents, POST /web/messages) and runs gsoci.azurecr.io/giantswarm/klaus-gateway:1.5.0 by default. The Slack-only release (giantswarm/klaus-gateway#319) removed the web channel; the current line is 3.x. The proof cannot exercise any current gateway build, so a klaus-gateway change cannot be proven in the lab.

The component half breaks too: the meta chart's components.klaus-gateway range is >=2.0.0 <4.0.0, the 3.x chart's values schema is closed and has no web key, so the lab's klausGateway.web.enabled: true fails the HelmRelease, and step 9 drives the component's web channel.

What stands in the way of driving Slack instead is the identity: the Slack channel forwards only a linked person's token (no service-account fallback), and a real OBO sign-in cannot complete in the lab (docs/klaus-gateway.md, "What the lab cannot prove").

Proposed solution

  • Drive the Slack adapter. The proof runs a fake Slack Web API (--slack-api-base): auth.test answers the bot user, users.info the lab user's e-mail, everything else {"ok":true,"ts":…}, and it records chat.postMessage, chat.update, chat.startStream/appendStream/stopStream, reactions.*, agents.sessions.setStatus per thread, so the assertions read what the thread would show. Messages are Events API callbacks to POST /channels/slack/events, signed with the run's signing secret (v0= HMAC-SHA256 over v0:<ts>:<body>); Approve and Deny are Block Kit clicks on POST /channels/slack/interactions.
  • Identity: seed the link store with the person's cached token. The proof writes a link for its Slack user through the gateway's own store package (pkg/auth/musterlink) — the Dex subject and e-mail, the lab user's Dex id_token as the link's cached id_token, its exp as expiry, a placeholder refresh token. Linker.TokenFor serves a cached, unexpired id_token without calling muster, the path a linked person's turn takes between refreshes, so the gateway runs unmodified. Host mode seals it into the run's bolt link store; the component into its link Secret with the lab's store-key (step 7 already writes there).
    • Rejected: a link whose refresh yields the lab user's token. It needs a muster refresh token issued to the gateway's OAuth client. muster identifies that client by CIMD and refuses a CIMD client_id on the lab's private-IP hostnames, so it takes a DCR client at muster and a headless walk through muster's authorize, the Dex login form and the callback: lab-only machinery for a refresh the gateway's unit tests already cover.
    • Rejected: a lab-only token source in the gateway (a token-file flag): product code that exists for the lab only, next to the rule that forbids a Slack turn any credential but the person's.
    • Consequence: the refresh leg (muster's token endpoint, rotation) stays out of the lab's reach and is documented so; the proof requires the token to outlive the run and asserts no token_refresh record.
  • The component drops web.enabled; a lab postRenderer points its KLAUS_GATEWAY_SLACK_API_BASE at a selector-less Service the proof aims at its fake during the run. Step 9 becomes one signed event through a port-forward, answered in the fake thread over the in-cluster target. The component's pods reach the fake as a container on the kind network (the proof's own binary), never through a port on the host. A probe pod checks the path first.
  • Default image: the current release, klaus-gateway:3.5.1.

Acceptance criteria

  • Host mode passes against the default image and a --gateway-binary build of klaus-gateway main:
    1. Discovery: @bot /agent lists the fixture's display name and not the unadmitted template; /agent <unadmitted> answers with no Harness admits and creates no AgentInstance; an unlinked Slack user is shown the Sign in button and reaches no controller.
    2. An attributed turn: the answer streams under the template's display name and icon; instance_bound names the thread's only AgentInstance; turn_dispatch carries the lab user's e-mail; muster logs the forwarded id_token accepted and the tool calls under the person's subject.
    3. HITL: Approve (hitl_approve) resumes the paused task in place to completed, the card reads Approved by; in a second thread Deny (hitl_deny) ends the task without the tool call reaching muster, the card reads Denied by.
    4. /stop in the thread: ⏹ Stopped., the task TASK_STATE_CANCELED at the controller, the next turn answers.
    5. A restart on the same stores continues the thread's AgentInstance with no new binding; no token_refresh record in the run.
  • With platform.klausGateway the component installs on the current meta chart; steps 6–8 unchanged; step 9 is a Slack turn through the pod.
  • docs/klaus-gateway.md, the "Swarmgeist proof" section of docs/platform.md and the unit tests describe the Slack-driven proof.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions