Skip to content

Commit 29fbbad

Browse files
committed
feat(ai): consume the identity code in the GitHub write-guard (#13275)
Per @neo-gpt's #13277 review: the write-guard's getGitHubIdentityErrorCode now keys on the core's stable IdentityAssertionCode (generic code -> GITHUB_* mapping) instead of reason.includes(...) string-matching. This retires the fragile prose-matching that #13275 set out to fix, so the PR fully delivers the write-guard-adoption AC and the close-target no longer overclaims. The spec's fake assertExpectedIdentity seams now faithfully return the core's code. The exact GITHUB_* output taxonomy is preserved.
1 parent c2ba1ef commit 29fbbad

2 files changed

Lines changed: 28 additions & 30 deletions

File tree

ai/mcp/server/github-workflow/toolService.mjs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import PullRequestService from '../../../services/github-workflow/PullRequestSer
1212
import RepositoryService from '../../../services/github-workflow/RepositoryService.mjs';
1313
import ToolService from '../../ToolService.mjs';
1414
import SyncService from '../../../services/github-workflow/SyncService.mjs';
15-
import {assertExpectedIdentity as assertExpectedGitHubIdentity} from '../../../graph/assertExpectedIdentity.mjs';
15+
import {assertExpectedIdentity as assertExpectedGitHubIdentity, IdentityAssertionCode} from '../../../graph/assertExpectedIdentity.mjs';
1616
import RequestContextService from '../shared/services/RequestContextService.mjs';
1717
import config from './config.mjs';
1818

@@ -137,32 +137,25 @@ function normalizeGitHubIdentityLogin(identity) {
137137
}
138138

139139
/**
140-
* @summary Maps the shared assertion reason into a stable write-boundary error code.
141-
* @param {String|null} reason Shared assertion reason.
140+
* @summary Maps the shared assertion's stable {@link IdentityAssertionCode} into a write-boundary
141+
* error code. Keys on the machine `code`, not the human-readable `reason` prose (which is free to
142+
* reword); an unknown or absent code falls back to the generic assertion-failed code.
143+
* @param {String} code The shared assertion's `code`.
142144
* @returns {String}
143145
*/
144-
function getGitHubIdentityErrorCode(reason) {
145-
if (!reason) {
146-
return 'GITHUB_IDENTITY_ASSERTION_FAILED';
146+
function getGitHubIdentityErrorCode(code) {
147+
switch (code) {
148+
case IdentityAssertionCode.EXPECTED_UNMAPPABLE:
149+
return 'GITHUB_IDENTITY_UNRESOLVED';
150+
case IdentityAssertionCode.NO_AUTHED_LOGIN:
151+
return 'GITHUB_VIEWER_UNRESOLVED';
152+
case IdentityAssertionCode.MEMORY_CORE_MISMATCH:
153+
return 'GITHUB_MEMORY_CORE_IDENTITY_MISMATCH';
154+
case IdentityAssertionCode.LOGIN_MISMATCH:
155+
return 'GITHUB_IDENTITY_MISMATCH';
156+
default:
157+
return 'GITHUB_IDENTITY_ASSERTION_FAILED';
147158
}
148-
149-
if (reason.includes('missing or unmappable')) {
150-
return 'GITHUB_IDENTITY_UNRESOLVED';
151-
}
152-
153-
if (reason.includes('no authed login')) {
154-
return 'GITHUB_VIEWER_UNRESOLVED';
155-
}
156-
157-
if (reason.includes('Memory-Core identity')) {
158-
return 'GITHUB_MEMORY_CORE_IDENTITY_MISMATCH';
159-
}
160-
161-
if (reason.includes('authed as')) {
162-
return 'GITHUB_IDENTITY_MISMATCH';
163-
}
164-
165-
return 'GITHUB_IDENTITY_ASSERTION_FAILED';
166159
}
167160

168161
/**
@@ -176,7 +169,7 @@ function createGitHubIdentityError(assertion) {
176169

177170
Object.assign(error, {
178171
...assertion,
179-
code: getGitHubIdentityErrorCode(assertion.reason)
172+
code: getGitHubIdentityErrorCode(assertion.code)
180173
});
181174

182175
return error;

test/playwright/unit/ai/services/github-workflow/toolService.spec.mjs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ test.describe('Neo.ai.services.github-workflow.toolService — write identity gu
244244
}, {
245245
assertExpectedIdentity: async () => ({
246246
ok : true,
247-
reason: null
247+
reason: null,
248+
code : 'OK'
248249
})
249250
});
250251

@@ -262,7 +263,8 @@ test.describe('Neo.ai.services.github-workflow.toolService — write identity gu
262263
}, {
263264
assertExpectedIdentity: async () => ({
264265
ok : false,
265-
reason: 'identity drift: authed as neo-opus-ada, expected neo-gpt'
266+
reason: 'identity drift: authed as neo-opus-ada, expected neo-gpt',
267+
code : 'LOGIN_MISMATCH'
266268
})
267269
});
268270

@@ -280,7 +282,8 @@ test.describe('Neo.ai.services.github-workflow.toolService — write identity gu
280282
}, {
281283
assertExpectedIdentity: async () => ({
282284
ok : false,
283-
reason: "identity drift: expected identity 'missing-agent' is missing or unmappable in identityRoots"
285+
reason: "identity drift: expected identity 'missing-agent' is missing or unmappable in identityRoots",
286+
code : 'EXPECTED_UNMAPPABLE'
284287
})
285288
});
286289

@@ -297,7 +300,8 @@ test.describe('Neo.ai.services.github-workflow.toolService — write identity gu
297300
}, {
298301
assertExpectedIdentity: async () => ({
299302
ok : false,
300-
reason: 'identity drift: no authed login resolved, expected neo-gpt'
303+
reason: 'identity drift: no authed login resolved, expected neo-gpt',
304+
code : 'NO_AUTHED_LOGIN'
301305
})
302306
});
303307

@@ -318,7 +322,8 @@ test.describe('Neo.ai.services.github-workflow.toolService — write identity gu
318322
}, {
319323
assertExpectedIdentity: async () => ({
320324
ok : false,
321-
reason: 'identity drift: authed as neo-opus-ada, expected neo-gpt'
325+
reason: 'identity drift: authed as neo-opus-ada, expected neo-gpt',
326+
code : 'LOGIN_MISMATCH'
322327
})
323328
});
324329

0 commit comments

Comments
 (0)