Commit 00235d1
authored
feat: project source-control bindings for member intent starts (#333)
* feat: project source-control bindings for member intent starts (#332)
Members could not start intents without a personal GitHub/GitLab
connection: the orchestrator resolved the starting user's token and
init-ws failed asynchronously (checkout_failed / intent_branch_push_failed).
Replace per-user runtime auth with project-level source-control bindings:
- Owners/admins bind each repository once, choosing GitHub App (per-repo
installation discovery) or explicitly confirmed github-oauth /
gitlab-oauth delegation at step 1 of the create-space flow; the App
path needs no personal connection at all (repo discovery runs on
App-JWT-minted metadata-read installation tokens via /github/app/*).
- Bindings hold opaque credential refs in a new DynamoDB table, never
tokens, and auto-invalidate when the delegator disconnects, loses
scopes, or leaves the project.
- Intent starts validate bindings up front (409 SOURCE_CONTROL_NOT_READY
with per-repo reasons) instead of failing mid-run.
- AgentCore runtime is token-free: git operations obtain short-lived
credentials from a credential-broker lambda (IAM-scoped to the runtime
role, validates execution liveness) via a throwaway GIT_ASKPASS
helper; tokens no longer enter invocation payloads or durable history.
- Provider API operations (branches, PRs, issues) route through a
source-control service lambda; per-provider API proxy routes and the
platform-wide GitHub auth mode are removed.
Also bumps js-yaml 4.2.0 -> 4.3.0 in the lockfile (GHSA-52cp-r559-cp3m,
pre-existing advisory that now trips the pre-commit audit).
Closes #332
* fix: address CodeQL findings on source-control logging and repo parsing (#332)
- Clear-text logging (js/clear-text-logging, alerts 17-20): error objects in
the credential-resolution path can carry provider-derived text. Logging
sites in credential-broker and source-control now emit only allowlisted
error-code constants via loggableErrorCode() and no longer log
error.message.
- Polynomial regex (js/polynomial-redos): canonicalRepo trimmed leading and
trailing slashes with /^\/+|\/+$/g over caller-supplied repo refs; replaced
with a linear-time scan.
* feat(source-control): allow GitHub App bindings without workflows:write
An installation lacking Workflows: Read & write previously failed binding
verification outright. There are valid reasons to withhold that permission,
so treat it as recommended instead of required: the binding verifies, the
reduced capability (workflows: none) is recorded on the binding, token mints
skip the ungranted permission (GitHub rejects mints requesting more than the
installation grants), and the project settings page shows a warning that the
agent cannot touch .github/workflows/.
* fix(git): survive concurrent GitLab token refreshes + restore 401 retry
Review feedback on #333 (two issues, one root cause: a transient credential
failure permanently invalidated the project binding).
1. GitLab refresh race: refresh tokens are one-time-use, and parallel
construction lanes each request credentials separately, so two concurrent
refreshes of the same connection burned each other — the loser got
invalid_grant, which the broker escalated to binding invalidation.
- ensureFreshGitToken now single-flights refreshes per connection within
a container (shared in-flight promise).
- On invalid_grant, refreshGitlabToken re-reads the stored pair before
failing: if it rotated, another request (possibly another container)
won the race — return its token instead of throwing. Only a genuinely
revoked (un-rotated) pair still fails.
2. Project-bound GitLab operations lost the personal handler's 401
refresh-and-retry: providers were invoked with a bare {token} ctx, so an
early/clock-skew 401 invalidated the binding as provider_unauthorized.
resolveBindingCredential now returns a refresh callback for gitlab-oauth
bindings (force-refresh past the rejected token, race-safe via staleToken)
and the source-control lambda wires it into ctx.onRefresh for both
operations and live validation. The broker response shape is unchanged.
Tests: concurrent-refresh single-flight, cross-container race recovery,
genuine revocation still failing, staleToken force/rotation semantics, and
the requested end-to-end test firing two concurrent broker requests for an
expired GitLab token (one refresh, both succeed, no binding invalidation).
* style: format credential-broker race test
* fix(source-control): stop gating GitHub App bindings on user-style repo permissions
Bind-and-verify failed with INSUFFICIENT_REPOSITORY_ACCESS for a GitHub App
installed on all repositories with Contents: Read & write. GET /repos returns
user-authority-shaped `permissions` (push/admin) that are absent or all-false
for an installation token, so access.canWrite is not a reliable signal on the
App path.
Write authority is already proven before the probe runs:
validateGitHubAppInstallation requires contents:write on the installation,
and the repo-scoped contents:write mint succeeds only when GitHub grants it.
Keep the GET /repos probe (it still fails the binding when the installation
cannot see the repository — 404/403) but stop requiring canWrite from it on
github-app bindings, in both verifyGitHubAppBinding and the live
validate-project check.1 parent a3c895b commit 00235d1
87 files changed
Lines changed: 6974 additions & 4396 deletions
File tree
- docs
- getting-started
- using-the-platform
- frontend/src
- components
- admin
- tabs
- project-settings
- pages
- services
- lambda
- agentcore
- commands
- test
- credential-broker
- test
- github
- test
- gitlab/test
- intents
- test
- projects
- source-control
- test
- trackers
- providers
- test
- users
- v2-orchestrator
- test
- terraform
- modules
- api
- lambda
- compute/agentcore
- git
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
118 | | - | |
| 118 | + | |
119 | 119 | | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
| 120 | + | |
124 | 121 | | |
125 | 122 | | |
126 | 123 | | |
| |||
132 | 129 | | |
133 | 130 | | |
134 | 131 | | |
135 | | - | |
| 132 | + | |
136 | 133 | | |
137 | | - | |
| 134 | + | |
138 | 135 | | |
139 | | - | |
140 | | - | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
141 | 142 | | |
142 | 143 | | |
143 | 144 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
| 18 | + | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | | - | |
23 | | - | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
24 | 27 | | |
25 | | - | |
| 28 | + | |
26 | 29 | | |
27 | 30 | | |
28 | 31 | | |
29 | | - | |
| 32 | + | |
30 | 33 | | |
31 | 34 | | |
32 | 35 | | |
| |||
38 | 41 | | |
39 | 42 | | |
40 | 43 | | |
41 | | - | |
42 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
43 | 47 | | |
44 | | - | |
| 48 | + | |
45 | 49 | | |
46 | 50 | | |
47 | 51 | | |
| |||
81 | 85 | | |
82 | 86 | | |
83 | 87 | | |
84 | | - | |
| 88 | + | |
85 | 89 | | |
86 | 90 | | |
87 | 91 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | | - | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
26 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
27 | 32 | | |
28 | 33 | | |
29 | 34 | | |
| |||
36 | 41 | | |
37 | 42 | | |
38 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
39 | 59 | | |
40 | 60 | | |
41 | 61 | | |
| 62 | + | |
42 | 63 | | |
| 64 | + | |
43 | 65 | | |
44 | 66 | | |
45 | 67 | | |
46 | 68 | | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
47 | 77 | | |
48 | 78 | | |
49 | 79 | | |
| |||
95 | 125 | | |
96 | 126 | | |
97 | 127 | | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
98 | 187 | | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
99 | 224 | | |
100 | 225 | | |
101 | 226 | | |
0 commit comments