Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
450 commits
Select commit Hold shift + click to select a range
e3fdb53
feat: add custom qualified Azure installer image refs (#682)
sabbour Aug 2, 2026
adf22a5
chore(release): sync v0.16.0 metadata to dev (#685)
sabbour Aug 2, 2026
7797a39
fix(azure): use FQDN-based Cilium egress for public-mode Postgres (#686)
sabbour Aug 2, 2026
1295cfb
fix(azure): parse list-skus array shape in Postgres SKU pre-flight (#…
sabbour Aug 2, 2026
6314349
fix(auth): server/info endpoint 401s and omits auth_mode, breaking En…
sabbour Aug 2, 2026
073d9f9
fix(auth): add missing GET /api/auth/session endpoint, surface Entra …
sabbour Aug 2, 2026
20b4aae
feat(demo): add Azure AKS capture plan (#698)
sabbour Aug 2, 2026
30380e1
docs: add Scenario 1 demo capture plan (#699)
sabbour Aug 2, 2026
07c3598
fix(api): add missing Postgres migration for dismissed_notifications …
sabbour Aug 2, 2026
78051cc
chore(release): sync v0.16.1 metadata to dev (#703)
sabbour Aug 2, 2026
9c2eecb
fix(auth): resolve the active linked GitHub account's token, and allo…
Copilot Aug 3, 2026
5f4892b
fix(demo): use regional Speech synthesis endpoint (#700)
sabbour Aug 9, 2026
3a202ae
fix(deploy): wire AUTH_MODE/ENTRA_CLIENT_ID/ENTRA_TENANT_ID through p…
sabbour Aug 9, 2026
f71de27
chore(release): sync v0.16.2 metadata to dev (#708)
sabbour Aug 9, 2026
c832c0e
feat(azure): add --image-source ghcr to deploy-from-release (#709)
sabbour Aug 9, 2026
082b216
fix(ui-harness): reject auth loading captures (#720)
sabbour Aug 10, 2026
256bdc7
test(preview): cover direct-backed retention lifecycle (#560) (#732)
sabbour Aug 10, 2026
71b040e
docs(auth): architecture plan for retiring hardcoded auth-middleware …
sabbour Aug 11, 2026
6caa057
fix(demo): require Edge Default for Entra recording (#710)
sabbour Aug 11, 2026
75a2acb
fix(webhooks): provision GitHub webhooks automatically (#722)
sabbour Aug 11, 2026
d6d5c7c
fix(assistant): propagate Entra identity to MCP (#723)
sabbour Aug 11, 2026
04c8cfb
fix(release): share publish cleanliness policy (#725)
sabbour Aug 11, 2026
56e3544
docs(sandbox): specify secure rootless BuildKit image builds (#726)
sabbour Aug 11, 2026
0bf2e14
fix(azure): select supported monitoring location (#727)
sabbour Aug 11, 2026
6493f7b
fix(sandbox): allow contained absolute preview cwd (#728)
sabbour Aug 11, 2026
9ac9a97
fix(a2a): structure terminal failures across remoted roles (#734)
sabbour Aug 11, 2026
41975fa
fix(auth): recover preview credential tombstones (#735)
sabbour Aug 11, 2026
75d5b9c
fix(web): preserve sidebar identity beside versions (#737)
sabbour Aug 11, 2026
5962680
fix(runtime): recover AgentHost auth and reaped pods (#738)
sabbour Aug 11, 2026
75314ba
fix(memory): enforce provenance trust boundary (#745)
sabbour Aug 11, 2026
2845206
fix(release): synchronize package-lock during prepare (#747)
sabbour Aug 11, 2026
87d8d7e
chore(release): sync v0.17.0 metadata to dev (#750)
sabbour Aug 11, 2026
73b1940
fix(release): validate both package-lock version mirrors (#749)
sabbour Aug 11, 2026
cac2e20
perf(ci): stack 1/3 — share safe worktree dependencies (#743)
sabbour Aug 11, 2026
85f76da
fix(ci): correct #743 cache invalidation generation (#752)
sabbour Aug 11, 2026
28ef024
docs: clarify agent-turn failures and memory trust (#753)
sabbour Aug 11, 2026
d47df1c
feat(ui-harness): add pointer drag primitive (#729)
sabbour Aug 12, 2026
bbb6dac
fix(sandbox): consolidate preview lifecycle protection (#731)
sabbour Aug 12, 2026
a0bfd98
fix(workflows): support multiple automation triggers (#724)
sabbour Aug 12, 2026
0d6aa2c
fix(sandbox): isolate Kata AgentHost child mounts (#744)
sabbour Aug 12, 2026
adbd83f
feat(preview): make approval timeout configurable and retryable (#742)
sabbour Aug 12, 2026
7db4f17
fix(workflows): surface schedules in visual editor (#730)
sabbour Aug 12, 2026
615266f
fix(auth): authorize project runs through project roles (#721)
sabbour Aug 12, 2026
47f6405
fix(ui-harness): persist browser sessions across actions (#733)
sabbour Aug 12, 2026
a476cc9
fix(web): switch linked GitHub accounts successfully (#719)
sabbour Aug 12, 2026
857910e
fix(workflows): align editor node types (#670) (#736)
sabbour Aug 12, 2026
ee2848c
chore(release): sync v0.18.0 metadata to dev
sabbour Aug 12, 2026
3cae2ee
fix(sandbox): unblock AgentHost warm pool on real AKS Kata with a har…
sabbour Aug 13, 2026
6568b87
feat(sandbox): give Kata runs a real Linux developer toolchain (apt, …
sabbour Aug 13, 2026
b41803a
chore(release): sync v0.18.1 metadata to dev (#765)
sabbour Aug 13, 2026
f0c53da
fix(web): GitHub account filter + Edge Default harness login (#766)
sabbour Aug 14, 2026
7c6e24c
fix(web): shell approval Allow once — correct isShell detection, coor…
sabbour Aug 14, 2026
9bb5e85
chore(release): sync v0.18.2 metadata to dev (#769)
sabbour Aug 14, 2026
8637ad2
chore(release): drop changesets already shipped in v0.18.2 (#770)
sabbour Aug 14, 2026
1d83edf
fix(projects): shallow clone GitHub project creation (#772)
sabbour Aug 17, 2026
e2f64da
docs(demo): add Azure capture retry handoff (#773)
sabbour Aug 17, 2026
d5be13e
docs(demo): codify Blueprint clean-run readiness (#775)
sabbour Aug 17, 2026
f2d84c3
fix(harness): diagnose Entra auth failures (#778)
sabbour Aug 18, 2026
0ecfbd3
fix(ci): cover demo recording tests (#781)
sabbour Aug 18, 2026
1c3c608
fix(demo): repair Blueprint recording continuity (#779)
sabbour Aug 18, 2026
dd56e0f
fix(demo): allow measured Blueprint planning duration (#782)
sabbour Aug 18, 2026
fdca93e
fix(demo): bound Blueprint staging timing variance (#783)
sabbour Aug 18, 2026
cff3d6b
fix: stabilize latency duration unit rounding (#788)
sabbour Aug 18, 2026
1eec73b
fix(demo): isolate Entra handoff capture (#793)
sabbour Aug 18, 2026
cd69c71
fix(demo): enforce 2.2 promotion confirmation order (#786)
sabbour Aug 18, 2026
052afa1
fix(demo): target Blueprint cadence combobox (#794)
sabbour Aug 18, 2026
54bb87b
fix(demo): enforce AKS fixture capture order (#795)
sabbour Aug 18, 2026
0d44d59
docs: define recorder Entra boundary (#799)
sabbour Aug 18, 2026
89d48e6
fix(demo): scope capture prerequisites to selected beats (#801)
sabbour Aug 18, 2026
dfa9cf6
fix(demo): defer Bug Fix PR resolution (#798)
sabbour Aug 18, 2026
801945a
fix(demo-recording): keep Entra sign-in shell available (#803)
sabbour Aug 18, 2026
ee319dc
fix(demo): gate sabbour/AKS capture sequence (#790)
sabbour Aug 19, 2026
1c85db3
fix(demo): isolate final fixture takes (#791)
sabbour Aug 19, 2026
aaf4900
fix(workflows): reject verdict nodes as workflow starts (#771)
sabbour Aug 19, 2026
73beffa
fix(squad): align repository casting layout (#780)
sabbour Aug 19, 2026
c679cf5
fix(demo): isolate recording profile authentication (#776)
sabbour Aug 19, 2026
795a1ba
fix: persist terminal WorkPlan status when coordinator run already st…
sabbour Aug 19, 2026
c27c4fd
fix(demo): harden recording capture integration (#805)
sabbour Aug 20, 2026
4cc099d
fix: surface GitHub token expiry prominently and improve renewal fail…
sabbour Aug 20, 2026
1de7c3f
fix(release): allow demo recording artifacts in clean-tree guard (#813)
sabbour Aug 20, 2026
b8ab020
feat(auth): GitHubLegacy adopt-session-token endpoint (#814)
sabbour Aug 20, 2026
9054667
fix(deploy): auto-load params.<username>.json for deploy-from-local (…
sabbour Aug 20, 2026
8e482b3
fix(auth): treat 401/403 Copilot probe as inconclusive, not unentitle…
sabbour Aug 20, 2026
23e0732
fix: null-guard legacy history.json deserialization (NullReferenceExc…
sabbour Aug 20, 2026
35953f5
fix: correct stale changeset package name (@agentweaver/api to agentw…
sabbour Aug 20, 2026
8dfbc88
fix(deploy): guard against empty Entra config in buildRuntimeConfigLi…
sabbour Aug 20, 2026
38ce83f
fix(skills): shallow-clone GitHub tree URLs for faster skill import (…
sabbour Aug 21, 2026
dd74a30
demo: blueprint capture plan fixes + api.mjs baseUrl fallback (#825)
sabbour Aug 21, 2026
5ba08d6
demo: fix beat 2.5 run-card selector + beat 2.2 Direct-mode cleanup (…
sabbour Aug 21, 2026
8a3434c
demo: remove auto-approve from beat 2.2, fix beat 2.5 startUrl + prer…
sabbour Aug 21, 2026
41d54c0
fix: use project URL template for beats 2.6-3.2 startUrl (#828)
sabbour Aug 21, 2026
3e31251
fix: resolve blueprint-demo capture plan merge conflict (expand beats…
sabbour Aug 21, 2026
a10cf89
fix(demo): beat 5.1 navigate to Account settings for mcp-server-url (…
sabbour Aug 21, 2026
4c7dc00
fix(demo): beats 3.1+3.2 use non-built-in workflow copies (#831)
sabbour Aug 21, 2026
acb84b5
feat: copy-on-write for built-in workflows (edit/schedule/event) (#834)
sabbour Aug 21, 2026
79d5073
fix: shallow-clone + NullRef guard for skill import speed (#833)
sabbour Aug 21, 2026
dadeac7
fix(demo): aks plan story gaps (#835)
sabbour Aug 21, 2026
e007ee1
fix(demo): blueprint plan - beat 2.1/2.5/2.7/3.x/4.2 content and sele…
sabbour Aug 21, 2026
57c6299
fix(demo): blueprint beat 2.2 - add Confirm plan button click after A…
sabbour Aug 21, 2026
2ec55b6
fix(demo): auto-switch to approval panel + simplify beat 2.5 plan (#838)
sabbour Aug 22, 2026
3556ffe
fix(demo): beat capture fixes and narration scripts (#839)
sabbour Aug 22, 2026
a8d1924
fix(demo-recording): extend hold time on beats 2.4, 4.2, 4.3 to meet …
sabbour Aug 22, 2026
bc9c903
fix(demo-recording): replace hardcoded staging IDs with env-var place…
sabbour Aug 22, 2026
362e98b
fix(demo-recording): allow template placeholder startUrls in assertPl…
sabbour Aug 22, 2026
0575d91
fix: preview runner crash (#844)
sabbour Aug 24, 2026
fc47339
fix: protect preview runners from Node OOM kills (#846)
sabbour Aug 24, 2026
295f0c1
fix(sandbox): increase shell watchdog grace and default timeout for K…
sabbour Aug 24, 2026
ef2de84
Trace view: show tool arguments/output and AIC cost per span (#853)
sabbour Aug 24, 2026
71869ee
feat: add Change option to Human review approval card (#855) (#856)
sabbour Aug 24, 2026
78e8890
fix: show display name instead of GUID in confirmedBy fields (#854)
sabbour Aug 24, 2026
f520f12
chore: add Dependabot configuration (#858)
sabbour Aug 24, 2026
02a5c12
chore(deps): Bump actions/setup-node from 4 to 7 (#859)
dependabot[bot] Aug 24, 2026
7627e63
chore(deps): Bump @types/node from 26.1.1 to 26.2.0 (#864)
dependabot[bot] Aug 24, 2026
f7790f5
chore(deps): Bump the npm_and_yarn group across 3 directories with 5 …
dependabot[bot] Aug 24, 2026
2583d3c
chore(deps): Bump postcss from 8.5.17 to 8.5.26 in /apps/web (#877)
dependabot[bot] Aug 24, 2026
a415cac
fix(sandbox): block spawn until sidecar confirms start to fix observe…
sabbour Aug 24, 2026
07e669d
chore(deps): Bump @testing-library/user-event from 14.6.1 to 14.6.4 i…
dependabot[bot] Aug 24, 2026
89e964a
fix(api): install GitHub CLI in runtime image (#851)
sabbour Aug 24, 2026
f06ddae
chore(deps): Bump actions/github-script from 7 to 9 (#865)
dependabot[bot] Aug 24, 2026
237fd73
chore(deps): Bump coverlet.collector from 6.0.2 to 10.0.1 (#875)
dependabot[bot] Aug 24, 2026
fed9389
chore(deps): Bump the npm_and_yarn group across 1 directory with 3 up…
dependabot[bot] Aug 24, 2026
642ad1b
fix(ci): update deprecated CodeQL action to v4 (#883)
sabbour Aug 24, 2026
ab10166
chore(deps): Bump playwright from 1.61.1 to 1.62.1 (#862)
dependabot[bot] Aug 24, 2026
abe1b07
chore(deps): Bump @changesets/cli from 2.31.0 to 3.0.0 (#866)
dependabot[bot] Aug 24, 2026
2995a39
chore(deps): Bump @vitejs/plugin-react from 6.0.3 to 6.0.5 in /apps/w…
dependabot[bot] Aug 24, 2026
ddb4244
chore(deps): Bump happy-dom from 20.10.6 to 20.11.2 in /apps/web (#871)
dependabot[bot] Aug 24, 2026
ab0c6c7
chore(deps): Bump the react-ecosystem group in /apps/web with 5 updat…
dependabot[bot] Aug 24, 2026
94578c3
chore(deps): Bump react-router and react-router-dom in /apps/web (#884)
dependabot[bot] Aug 24, 2026
77e3f06
chore(deps): Bump actions/upload-pages-artifact from 3 to 5 (#861)
dependabot[bot] Aug 24, 2026
dbaf866
chore(deps): Bump actions/setup-dotnet from 4 to 6 (#863)
dependabot[bot] Aug 24, 2026
501d756
chore(deps): Bump actions/cache from 4 to 6 (#860)
dependabot[bot] Aug 24, 2026
0986261
chore(release): sync v0.19.0 release metadata to dev (#885)
sabbour Aug 24, 2026
28d34d3
fix: keep Trivy SARIF uploads healthy (#879)
sabbour Aug 24, 2026
ffcd870
fix(ux): replace raw identity GUID with display name in outcome plan …
sabbour Aug 25, 2026
9643764
chore(deps): Bump the fluent-ui group in /apps/web with 2 updates (#868)
dependabot[bot] Aug 25, 2026
13d25a1
fix(ux): correct trace summary latest date, sort runs newest-first, a…
sabbour Aug 25, 2026
7c8a89a
fix(sandbox): raise handshake timeout to exceed writable-root wait; a…
sabbour Aug 25, 2026
d4418dd
chore(deps): Bump Microsoft.AspNetCore.Mvc.Testing and 9 others (#872)
dependabot[bot] Aug 25, 2026
b0d1307
chore(deps): Bump the azure-sdk group with 5 updates (#873)
dependabot[bot] Aug 25, 2026
367b0ac
chore(deps): Bump the opentelemetry group with 2 updates (#874)
dependabot[bot] Aug 25, 2026
453675a
fix(observability): record tool call arguments and output in trace sp…
sabbour Aug 25, 2026
b4a1eaa
fix(tests): sync deploy-render CPU expectations with PR #886 rebalanc…
sabbour Aug 25, 2026
8dd0559
chore(release): sync v0.19.1 release metadata to dev (#893)
sabbour Aug 25, 2026
96ad613
fix(web): handle tool.approval_context in timeline reducer (#894)
sabbour Aug 25, 2026
bbb9396
fix(ci): use GHCR instead of ACR in agent-host-maintenance workflow (…
sabbour Aug 25, 2026
15ae5b9
fix(deps): bump Copilot SDK to 1.0.11 with compatible MAF adapter (#898)
sabbour Aug 25, 2026
3fdaa24
feat(deploy): default image source to GHCR across deployment scripts …
sabbour Aug 25, 2026
d00bf2d
chore(release): sync v0.19.2 release metadata to dev (#900)
sabbour Aug 25, 2026
41d98a1
fix(deps): align Microsoft Agent Framework packages to 1.19.x (Workfl…
sabbour Aug 25, 2026
4acfc9a
fix(ci): set rebase-strategy: disabled on all Dependabot entries (#901)
sabbour Aug 25, 2026
5bfae29
fix(ci): scope .github/workflows path filter to ci.yml; remove echo w…
sabbour Aug 25, 2026
36f230b
perf(ci): gate docs-drift on paths; scope publish-images to changed i…
sabbour Aug 25, 2026
0cc6ff3
perf(ci): cache playwright/apt, draft-gate expensive jobs, consolidat…
sabbour Aug 25, 2026
16bc62b
fix: reorder Kata CI gate before full suite + fix 4 flaky sandbox tes…
sabbour Aug 25, 2026
059098b
fix(ci): backport #926 — move matrix.name guard to step-level if (#927)
sabbour Aug 25, 2026
20f1481
chore(squad): upgrade Squad v0.10.0 to v0.12.0 + externalize state (#…
sabbour Aug 25, 2026
70b653f
fix(sandbox): raise agentweaver-exec memory limit 2Gi→4Gi to prevent …
sabbour Aug 25, 2026
41d9322
fix(observability): set gen_ai.tool.call.arguments and .result on exe…
sabbour Aug 26, 2026
5074e00
fix: sticky plan footer + TeamPage cold-start race + capture plan bea…
sabbour Aug 26, 2026
1055098
docs: replace Review Policy UI with workflow gate documentation (#935)
sabbour Aug 26, 2026
c1d55a2
fix: use per-user GitHub identity instead of static project override …
sabbour Aug 26, 2026
cc6d464
docs: define two GitHub App contracts (#953)
sabbour Aug 27, 2026
217577d
feat: add two-App persistence foundation (#954)
sabbour Aug 27, 2026
5915f62
fix(auth): harden two-App identity persistence (#956)
sabbour Aug 27, 2026
9431463
feat(auth): add Repo App user authorization (#957)
sabbour Aug 27, 2026
08e02f8
feat: add Repo App installation lifecycle (#959)
sabbour Aug 27, 2026
f0a6139
fix: atomically reclaim stale webhook claims (#960)
sabbour Aug 27, 2026
7e3d446
feat(auth): add project Copilot bindings (#958)
sabbour Aug 27, 2026
7db37f1
fix: derive Repo App installation authority (#963)
sabbour Aug 27, 2026
15ef610
feat(auth): enforce immutable broker snapshots (#962) (#964)
sabbour Aug 27, 2026
b7df33f
feat(auth): add purpose-bound GitHub credential broker (#965)
sabbour Aug 28, 2026
44e0fc8
feat: add unattended project settings and diagnostics (#966)
sabbour Aug 28, 2026
4cc0cc3
feat/947 sandbox repo credential (#968)
sabbour Aug 28, 2026
3c59232
fix(coordinator): stop terminal orphan re-arms (#969)
sabbour Aug 28, 2026
12bda78
fix(sandbox): verify Kata shell timeout handling (#970)
sabbour Aug 28, 2026
4a1daf9
fix: route approval notifications to the correct run (#971)
sabbour Aug 28, 2026
3022a35
docs: define coordinated gh stack workflow
sabbour Aug 28, 2026
d978b4a
docs: add gh stack workflow details (#975)
sabbour Aug 28, 2026
a34bb60
docs: align stack overlay with official skill
sabbour Aug 28, 2026
2c55e89
feat(web): add safe Copilot authorization feedback
sabbour Aug 28, 2026
9b9ee1c
fix(approvals): persist approval scopes
sabbour Aug 28, 2026
5add57e
test: add Fleet cutover validation matrix
sabbour Aug 28, 2026
daf7152
feat(mcp): add two-App capability handoffs (#979)
sabbour Aug 28, 2026
52fc656
test: shard .NET CI suite
sabbour Aug 28, 2026
31d6df7
test: complete pickup ownership stream (#983)
sabbour Aug 28, 2026
0a972d4
feat: issue GitHub repository selection codes (#945) (#978)
sabbour Aug 28, 2026
498fa42
fix(projects): enforce GitHub selection codes (#980)
sabbour Aug 28, 2026
cc695c2
test: trim application startup waits (#985)
sabbour Aug 28, 2026
915505a
fix(tests): synchronize image build socket probe (#989)
sabbour Aug 28, 2026
3e9d41a
fix(ci): run .NET shards for draft stacks (#990)
sabbour Aug 28, 2026
0c44256
test: complete Foundry watchdog fixture (#991)
sabbour Aug 28, 2026
97027a3
feat: add fenced automation activation snapshots (#986)
sabbour Aug 28, 2026
cccfa29
feat: fence automation invocation boundary (#987)
sabbour Aug 28, 2026
c014960
feat(auth): retire legacy OAuth core (#992)
sabbour Aug 29, 2026
e9fe264
refactor: broker runtime GitHub credentials (#993)
sabbour Aug 29, 2026
7bbe99c
feat(auth): remove legacy OAuth surfaces (#994)
sabbour Aug 29, 2026
e3230d8
fix(ci): emit .NET shard contexts on every dev PR (#998)
sabbour Aug 29, 2026
743c7ea
chore(release): sync v0.20.0 release metadata to dev
sabbour Aug 29, 2026
1531361
fix(migrations): use injected Postgres configuration (#1000)
sabbour Aug 29, 2026
9e9f7f8
chore(release): sync v0.21.0 release metadata to dev
sabbour Aug 29, 2026
9b8defb
fix(auth): restore GitHub account picker (#1002)
sabbour Aug 29, 2026
d9ac7f0
fix(api): tolerate unavailable run artifacts (#1013)
sabbour Aug 29, 2026
b2e6495
fix(workflow-editor): preserve selection during edits (#1015)
sabbour Aug 29, 2026
416054a
fix(web): suppress partial outcome-plan JSON stream (#1012)
sabbour Aug 29, 2026
cdcf581
fix(auth): require public Entra origins (#1014)
sabbour Aug 29, 2026
3412759
fix: fence AgentHost launch capabilities and retry feedback (#1016)
sabbour Aug 29, 2026
74a9b0a
fix: repair Kata executor socket after the 2026-08-27 node image / Ka…
sabbour Aug 29, 2026
7687d44
chore(release): sync v0.21.3 metadata to dev (#1021)
sabbour Aug 29, 2026
9cd9274
fix: clean stale frontend build stashes (#1022)
sabbour Aug 30, 2026
8ee1970
Fix GitHub App credential capability reads (#1023)
sabbour Aug 30, 2026
c3524b8
chore(release): sync v0.21.4 metadata to dev (#1025)
sabbour Aug 30, 2026
95b965d
fix(k8s): wire GitHub Copilot/Repo App secrets into production deploy…
sabbour Aug 30, 2026
9c4887d
Update ACR description to GHCR in workflow (#899)
sabbour Aug 30, 2026
761cf98
fix(web): restore sidebar GitHub identity indicator (#1027)
sabbour Aug 30, 2026
8610042
fix(auth): prevent Copilot App validation startup crash (#1028)
sabbour Aug 30, 2026
883fa92
docs: durable session decisions log for Copilot App auth fix (#1029)
sabbour Aug 30, 2026
39dc6da
fix: demo-recording session cache bloat + deploy-from-commit/release …
sabbour Aug 30, 2026
428bb6d
fix(github-app): case-insensitive credentials + restore repo connecti…
sabbour Aug 30, 2026
650e1b3
docs: update session decisions log with second round of GitHub auth f…
sabbour Aug 30, 2026
2e2e1a9
fix(k8s): wire GitHub App post-auth redirect URLs to production front…
sabbour Aug 30, 2026
d884f81
docs: record two more GitHub auth bugs found via live user testing (P…
sabbour Aug 30, 2026
5e62974
fix(auth): log root cause when Copilot App binding fails (#1035)
sabbour Aug 30, 2026
45fa95e
docs: record PR #1035 in decisions log (#1036)
sabbour Aug 30, 2026
fe6b9d8
Fix: wire up Key Vault URI for GitHub auth credential persistence (#1…
sabbour Aug 31, 2026
3c64aa9
feat: link account roles to Entra ID (#1041)
sabbour Aug 31, 2026
a0a1ccc
feat(web): visualize cluster resource topology (#1042)
sabbour Aug 31, 2026
f390805
fix: clarify GitHub connection errors and background wording (#1045)
sabbour Aug 31, 2026
48dfbe6
fix: recover worker dispatches after disruption (#1050)
sabbour Aug 31, 2026
f138c79
feat: clean up settings navigation (#1044)
sabbour Aug 31, 2026
8d896d2
fix(web): restore GitHub connection regression coverage (#1055)
sabbour Aug 31, 2026
03178ec
fix(scripts): delete generated demo-recording beat scripts after use …
sabbour Aug 31, 2026
61125af
feat: reclaim the workflow editor canvas (#1054)
sabbour Aug 31, 2026
91a44e0
fix: stabilize SkillsPage project transition tests (#1056)
sabbour Aug 31, 2026
9fc259e
fix(web): clarify plan submission feedback (#1051)
sabbour Aug 31, 2026
72bc6b6
feat: add account GitHub connections settings (#1046)
sabbour Aug 31, 2026
c900f4e
fix: separate background settings requirements (#1047)
sabbour Aug 31, 2026
a4da3b7
feat/auth ux status badge (#1048)
sabbour Aug 31, 2026
8d72b93
fix: reconcile outcome plan confirmation state (#1053)
sabbour Aug 31, 2026
f2b4442
fix: add close controls to dialogs (#1052)
sabbour Aug 31, 2026
4b4dbd6
fix(web): restore getAuthConfig/formActions dropped by merge (dev bui…
sabbour Aug 31, 2026
44e9a91
feat: deployment-wide BYOK inference provider (bring your own key) (#…
sabbour Aug 31, 2026
db37b64
feat(web): Platform settings page with AI mode switch and BYOK form (…
sabbour Aug 31, 2026
baa4e4d
feat: finish ModelSource step B rename (#1061)
sabbour Aug 31, 2026
988e0f1
refactor: rename internal TwoApp naming to GitHubConnections (#1062)
sabbour Aug 31, 2026
c936f8b
feat: platform-default GitHub Copilot connection + first-run AI locko…
sabbour Aug 31, 2026
123038d
fix: avoid forbidden legacy 'GitHub OAuth' phrase in configuration do…
sabbour Aug 31, 2026
7dd046c
fix: harden Copilot binding cleanup and config recovery (#1066)
sabbour Aug 31, 2026
5992613
chore(release): sync dev with v0.22.0 release preparation (#1067)
sabbour Aug 31, 2026
6139bc6
chore(release): prepare v0.22.1
sabbour Aug 31, 2026
65789c4
merge: resolve main into release/v0.22.1
sabbour Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.22.1

### Patch Changes

- 7dd046c: Harden GitHub Copilot platform-connection handling so malformed saved configuration does not block recovery, platform/default and project-scoped bindings safely clean up or preserve shared credentials, and SQLite-to-Postgres migration carries the platform-default binding forward reliably.

## 0.22.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.22.0
0.22.1
120 changes: 73 additions & 47 deletions apps/Agentweaver.Api/Auth/ByokProviderConfigurationService.cs
Original file line number Diff line number Diff line change
@@ -1,47 +1,73 @@
using System.Text.Json;
using Agentweaver.Domain;

namespace Agentweaver.Api.Auth;

public sealed class ByokProviderConfigurationService(ISecretStore secretStore)
: IByokProviderConfigurationProvider
{
private const string SecretName = "byok-provider-configuration";

public async Task<ByokProviderConfiguration?> GetAsync(CancellationToken ct)
{
var secret = await secretStore.GetSecretAsync(SecretName, ct).ConfigureAwait(false);
return secret.Found && !string.IsNullOrWhiteSpace(secret.Value)
? JsonSerializer.Deserialize<ByokProviderConfiguration>(secret.Value)
: null;
}

public async Task SetAsync(ByokProviderConfiguration configuration, CancellationToken ct)
{
Validate(configuration);
await secretStore.SetSecretAsync(
SecretName,
JsonSerializer.Serialize(configuration),
ct: ct).ConfigureAwait(false);
}

public Task ClearAsync(CancellationToken ct) =>
secretStore.DeleteSecretAsync(SecretName, ct);

private static void Validate(ByokProviderConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration);
if (configuration.Type is not ("openai" or "azure" or "anthropic"))
throw new ArgumentException("Provider type must be openai, azure, or anthropic.");
if (!Uri.TryCreate(configuration.BaseUrl, UriKind.Absolute, out var baseUri) ||
baseUri.Scheme != Uri.UriSchemeHttps)
throw new ArgumentException("Provider base URL must be an HTTPS URL.");
if (configuration.Type == "azure" &&
(!string.IsNullOrEmpty(baseUri.PathAndQuery.Trim('/')) || !string.IsNullOrEmpty(baseUri.Fragment)))
throw new ArgumentException("Azure provider base URL must be its HTTPS host without an API path.");
if (string.IsNullOrWhiteSpace(configuration.Model))
throw new ArgumentException("Provider model is required.");
if (string.IsNullOrWhiteSpace(configuration.ApiKey))
throw new ArgumentException("Provider API key is required.");
}
}
using System.Text.Json;
using Agentweaver.Domain;

namespace Agentweaver.Api.Auth;

public sealed class ByokProviderConfigurationService(ISecretStore secretStore)
: IByokProviderConfigurationProvider
{
private const string SecretName = "byok-provider-configuration";
private static readonly JsonSerializerOptions ReadJsonOptions = new() { PropertyNameCaseInsensitive = true };

public async Task<ByokProviderConfiguration?> GetAsync(CancellationToken ct)
{
var secret = await secretStore.GetSecretAsync(SecretName, ct).ConfigureAwait(false);
if (!secret.Found || string.IsNullOrWhiteSpace(secret.Value))
return null;
try
{
var configuration = JsonSerializer.Deserialize<ByokProviderConfiguration>(secret.Value, ReadJsonOptions);
return IsValid(configuration) ? configuration : null;
}
catch (JsonException)
{
return null;
}
}

public async Task SetAsync(ByokProviderConfiguration configuration, CancellationToken ct)
{
Validate(configuration);
await secretStore.SetSecretAsync(
SecretName,
JsonSerializer.Serialize(configuration),
ct: ct).ConfigureAwait(false);
}

public Task ClearAsync(CancellationToken ct) =>
secretStore.DeleteSecretAsync(SecretName, ct);

private static void Validate(ByokProviderConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration);
if (configuration.Type is not ("openai" or "azure" or "anthropic"))
throw new ArgumentException("Provider type must be openai, azure, or anthropic.");
if (!Uri.TryCreate(configuration.BaseUrl, UriKind.Absolute, out var baseUri) ||
baseUri.Scheme != Uri.UriSchemeHttps)
throw new ArgumentException("Provider base URL must be an HTTPS URL.");
if (configuration.Type == "azure" &&
(!string.IsNullOrEmpty(baseUri.PathAndQuery.Trim('/')) || !string.IsNullOrEmpty(baseUri.Fragment)))
throw new ArgumentException("Azure provider base URL must be its HTTPS host without an API path.");
if (string.IsNullOrWhiteSpace(configuration.Model))
throw new ArgumentException("Provider model is required.");
if (string.IsNullOrWhiteSpace(configuration.ApiKey))
throw new ArgumentException("Provider API key is required.");
}

private static bool IsValid(ByokProviderConfiguration? configuration)
{
try
{
Validate(configuration!);
return true;
}
catch (ArgumentNullException)
{
return false;
}
catch (ArgumentException)
{
return false;
}
}
}
172 changes: 87 additions & 85 deletions apps/Agentweaver.Api/Auth/GitHubConnectionsCredentialVault.cs
Original file line number Diff line number Diff line change
@@ -1,85 +1,87 @@
using System.Text.Json;

namespace Agentweaver.Api.Auth;

/// <summary>Opaque, vault-owned locator for reserved GitHub connections credential material.</summary>
internal sealed record GitHubConnectionsCredentialLocator
{
private GitHubConnectionsCredentialLocator(string key) => Key = key;

internal string Key { get; }

internal static GitHubConnectionsCredentialLocator ForRepoAppUser(string credentialReference) =>
Create(credentialReference, "repo-app-user-credential-");

internal static GitHubConnectionsCredentialLocator ForCopilotProject(string credentialReference) =>
Create(credentialReference, "copilot-app-project-");

internal static GitHubConnectionsCredentialLocator ForCopilotBinding(string credentialReference)
{
if (string.IsNullOrWhiteSpace(credentialReference) ||
(!credentialReference.StartsWith("copilot-app-project-", StringComparison.Ordinal) &&
!credentialReference.StartsWith("copilot-app-platform-default-", StringComparison.Ordinal)))
throw new ArgumentException("Credential reference is not a reserved GitHub connections locator.", nameof(credentialReference));
return new(credentialReference);
}

private static GitHubConnectionsCredentialLocator Create(string credentialReference, string requiredPrefix)
{
if (string.IsNullOrWhiteSpace(credentialReference) ||
!credentialReference.StartsWith(requiredPrefix, StringComparison.Ordinal))
throw new ArgumentException("Credential reference is not a reserved GitHub connections locator.", nameof(credentialReference));
return new(credentialReference);
}
}

internal interface IGitHubConnectionsCredentialVault
{
Task<SecretGetResult> ReadCurrentAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default);
Task WriteAsync(GitHubConnectionsCredentialLocator locator, string value, CancellationToken ct = default);
Task TombstoneAndDeleteAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default);
}

/// <summary>
/// The sole GitHub connections authority allowed to bridge reserved credential locators to generic secret
/// storage. Reads are current-version only and tombstones cannot be treated as a credential.
/// </summary>
internal sealed class GitHubConnectionsCredentialVault(ISecretStore secretStore) : IGitHubConnectionsCredentialVault
{
private const string Tombstone = """{"status":"revoked"}""";

public async Task<SecretGetResult> ReadCurrentAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default)
{
var result = await secretStore.GetSecretAsync(locator.Key, ct).ConfigureAwait(false);
return !result.Found || IsTombstone(result.Value) ? SecretGetResult.NotFound : result;
}

public async Task WriteAsync(GitHubConnectionsCredentialLocator locator, string value, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(value) || IsTombstone(value))
throw new ArgumentException("The vault cannot write empty or tombstone credential material.", nameof(value));
await secretStore.SetSecretAsync(locator.Key, value, ct: ct).ConfigureAwait(false);
}

public async Task TombstoneAndDeleteAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default)
{
await secretStore.SetSecretAsync(locator.Key, Tombstone, ct: ct).ConfigureAwait(false);
await secretStore.DeleteSecretAsync(locator.Key, ct).ConfigureAwait(false);
}

private static bool IsTombstone(string? value)
{
if (string.IsNullOrWhiteSpace(value))
return false;
try
{
using var document = JsonDocument.Parse(value);
return document.RootElement.TryGetProperty("status", out var status) &&
string.Equals(status.GetString(), "revoked", StringComparison.Ordinal);
}
catch (JsonException)
{
return false;
}
}
}
using System.Text.Json;

namespace Agentweaver.Api.Auth;

/// <summary>Opaque, vault-owned locator for reserved GitHub connections credential material.</summary>
internal sealed record GitHubConnectionsCredentialLocator
{
private GitHubConnectionsCredentialLocator(string key) => Key = key;

internal string Key { get; }

internal static GitHubConnectionsCredentialLocator ForRepoAppUser(string credentialReference) =>
Create(credentialReference, "repo-app-user-credential-");

internal static GitHubConnectionsCredentialLocator ForCopilotProject(string credentialReference) =>
Create(credentialReference, "copilot-app-project-");

internal static GitHubConnectionsCredentialLocator ForCopilotBinding(string credentialReference)
{
if (string.IsNullOrWhiteSpace(credentialReference) ||
(!credentialReference.StartsWith("copilot-app-project-", StringComparison.Ordinal) &&
!credentialReference.StartsWith("copilot-app-platform-default-", StringComparison.Ordinal)))
throw new ArgumentException("Credential reference is not a reserved GitHub connections locator.", nameof(credentialReference));
return new(credentialReference);
}

private static GitHubConnectionsCredentialLocator Create(string credentialReference, string requiredPrefix)
{
if (string.IsNullOrWhiteSpace(credentialReference) ||
!credentialReference.StartsWith(requiredPrefix, StringComparison.Ordinal))
throw new ArgumentException("Credential reference is not a reserved GitHub connections locator.", nameof(credentialReference));
return new(credentialReference);
}
}

internal interface IGitHubConnectionsCredentialVault
{
Task<SecretGetResult> ReadCurrentAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default);
Task WriteAsync(GitHubConnectionsCredentialLocator locator, string value, CancellationToken ct = default);
Task TombstoneAndDeleteAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default);
}

/// <summary>
/// The sole GitHub connections authority allowed to bridge reserved credential locators to generic secret
/// storage. Reads are current-version only and tombstones cannot be treated as a credential.
/// </summary>
internal sealed class GitHubConnectionsCredentialVault(ISecretStore secretStore) : IGitHubConnectionsCredentialVault
{
private const string Tombstone = """{"status":"revoked"}""";

public async Task<SecretGetResult> ReadCurrentAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default)
{
var result = await secretStore.GetSecretAsync(locator.Key, ct).ConfigureAwait(false);
return !result.Found || IsTombstone(result.Value) ? SecretGetResult.NotFound : result;
}

public async Task WriteAsync(GitHubConnectionsCredentialLocator locator, string value, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(value) || IsTombstone(value))
throw new ArgumentException("The vault cannot write empty or tombstone credential material.", nameof(value));
await secretStore.SetSecretAsync(locator.Key, value, ct: ct).ConfigureAwait(false);
}

public async Task TombstoneAndDeleteAsync(GitHubConnectionsCredentialLocator locator, CancellationToken ct = default)
{
await secretStore.SetSecretAsync(locator.Key, Tombstone, ct: ct).ConfigureAwait(false);
await secretStore.DeleteSecretAsync(locator.Key, ct).ConfigureAwait(false);
}

private static bool IsTombstone(string? value)
{
if (string.IsNullOrWhiteSpace(value))
return false;
try
{
using var document = JsonDocument.Parse(value);
return document.RootElement.ValueKind == JsonValueKind.Object &&
document.RootElement.TryGetProperty("status", out var status) &&
status.ValueKind == JsonValueKind.String &&
string.Equals(status.GetString(), "revoked", StringComparison.Ordinal);
}
catch (Exception ex) when (ex is JsonException or InvalidOperationException)
{
return false;
}
}
}
Loading
Loading