Step 4: credentials + post-to-site (Bluesky)#6
Merged
rockfordlhotka merged 2 commits intomainfrom Apr 22, 2026
Merged
Conversation
Fleshes out Foragent.Credentials with ICredentialBroker + CredentialReference(Id, Kind, Values), an in-memory broker bound to a "Credentials" config section (dev/test only per spec §6.3), and CredentialNotFoundException. Adds a third capability, post-to-site, that resolves a credential by id and dispatches to an ISitePoster keyed on the site input. BlueskySitePoster is the first (and only) implementation, driving the bsky.app web UI with app-password auth. IBrowserSession gains OpenPageAsync → IBrowserPage with navigate / fill / click / wait-for-selector / get-url / get-text primitives so the site poster can drive multi-step flows without taking a direct dependency on Microsoft.Playwright. Security invariants per spec §§6.1–6.2: credential values never cross A2A boundaries, never land in logs, never embed in exception messages. Post-to-site scrubs poster exception text before echoing failures to callers — operators see the full exception in logs. Deferred and tracked in docs/framework-feedback.md step 4: storage-state-as-credential (§6.5), 2FA input-required flow (§6.6), Kubernetes secrets broker (§6.3), per-tenant credential namespaces (§7.5), structured audit logging (§7.4), domain allowlists (§7.1). Tests (47 pass, 1 LLM-only skipped): - InMemoryCredentialBroker unit tests + ToString-scrubs-values - PostToSiteCapability unit tests with stub broker + poster - BlueskySitePoster integration test: real Chromium against a Kestrel-hosted fake bsky.app login + compose UI Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Real secret backends (k8s Secrets, cert stores, storage-state blobs) are byte-native; forcing text at the broker boundary loses fidelity for binary material. Switch Values to IReadOnlyDictionary<string, ReadOnlyMemory<byte>>. Add FromText() factory and RequireText() accessor for the common UTF-8 path so text-origin callers don't encode by hand. InMemoryCredentialBroker keeps text-native config binding (nobody types base64 into user-secrets) and UTF-8 encodes at the boundary. Also: document the three known gaps in the credential interface (list, write, tenancy) in docs/framework-feedback.md so they don't get rediscovered when the triggering capability lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
rockfordlhotka
added a commit
that referenced
this pull request
Apr 23, 2026
Ships the phase-1 / phase-3 form capability pair from spec §5.5 and
bumps the RockBot framework to 0.9.* for the multi-file skill API.
- FormSchema / FormField wire types with stable JSON serializer options.
- IBrowserPage.ScanFormAsync: single-JS-pass deterministic form read
(labels, validation attrs, select/radio options). Adds
SelectOptionAsync + SetCheckedAsync for the batch submit path.
- LearnFormSchemaCapability: navigate → deterministic scan →
FormSchemaEnricher (one LLM turn, can only add dependsOn + notes;
structural fields are DOM-authoritative) → persist as Skill with a
SkillResourceType.JsonSchema "schema.json" resource at
sites/{host}/forms/{slug}.
- ExecuteFormBatchCapability: resolves schema by skillRef via
ISkillStore.GetResourceAsync or inline; streams per-row progress via
AgentTaskContext.PublishStatus; default mode "abort-on-first"
(spec open-question #8 resolution), caller opts into "continue".
Success signal: optional successIndicator selector, URL-change
fallback.
- Package bump 0.8.* → 0.9.* (adds RockBot.Llm.Abstractions). Docker
image rockylhotka/rockbot-agent 0.8.5 → 0.9.11 so the peer side
gets PR #291 structured-data invoke_agent.
- Version scheme adopted: 0.2.0-alpha.8 in Directory.Build.props,
documented in CLAUDE.md Conventions.
- 14 unit tests + 1 Kestrel+Chromium end-to-end integration test.
Resolves spec open-questions #6 (typed artifacts — uses RockBot 0.9
resource files, no parallel Foragent store) and #8 (batch semantics —
abort-on-first default).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 4 per spec §9.1 — credential broker + first capability that needs it.
Foragent.Credentialsfleshed out:ICredentialBroker+CredentialReference(Id, Kind, Values)+CredentialNotFoundException.InMemoryCredentialBrokerbinds to aCredentialsconfig section (user-secrets in dev — never appsettings). Per spec §6.3, in-memory broker is dev/test only; k8s-secrets broker deferred. Tenancy is single-tenant; per-tenant credential namespaces (§7.5) deferred.IBrowserSession.OpenPageAsync→IBrowserPage— adds navigate / fill / click / wait-for-selector / get-url / get-text primitives so site posters can drive multi-step flows without depending on Microsoft.Playwright directly.post-to-sitecapability (third on the agent card) dispatches to anISitePosterkeyed on thesiteinput.BlueskySitePosteris the only implementation — drives the bsky.app web UI with app-password auth. Exception messages from posters are never echoed to callers (they could contain credential material); operators see the full exception in logs.CredentialReference.ToString()scrubs values,Require()errors name missing keys but not values,PostToSiteCapabilityreplaces the poster exception message with a generic failure string.docs/framework-feedback.mdstep 4 so nothing gets lost: storage-state-as-credential §6.5, 2FA input-required flow §6.6, k8s-secrets broker §6.3, per-tenant credential namespaces §7.5, structured audit logging §7.4, domain allowlists §7.1.Test plan
dotnet build --configuration Release— cleandotnet test— 47/47 pass (34 unit + 12 browser integration + 1 smoke; 1 LLM-only integration test skipped whenFORAGENT_LLM_*isn't set)BlueskySitePosterIntegrationTestsdrives real Chromium against a Kestrel-hosted fake bsky.app-shaped login + compose UIdocker compose up --build+ curl smoke test ofpost-to-siteagainst a configured Bluesky credential (next in this session)Known limitations
BlueskySitePosteruses exactrole=button[name="Sign in"]-style matches. Real-world bsky.app copy changes require a code update. Flagged in the framework-feedback doc.__separates config path segments, soCredentials__rockbot__social__bluesky-rocky__Kinddoesn't bind as an id. User-secrets / appsettings support arbitrary ids (slashes, etc.). Documented in CLAUDE.md.BlueskySitePosteris logged but scrubbed from A2A responses. The capability returns a generic "Post to bluesky failed." message; see logs for root cause.🤖 Generated with Claude Code