@humanbased/crosscheck 1.2.0-beta.80 โ 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +388 -149
- package/README.zh.md +1 -1
- package/crosscheck.config.example.yml +2 -63
- package/dist/__tests__/codex.test.js +27 -14
- package/dist/__tests__/codex.test.js.map +1 -1
- package/dist/__tests__/comment-bodies.test.js +1 -49
- package/dist/__tests__/comment-bodies.test.js.map +1 -1
- package/dist/__tests__/conflict-resolve.test.js +1 -44
- package/dist/__tests__/conflict-resolve.test.js.map +1 -1
- package/dist/__tests__/fix.test.js +0 -33
- package/dist/__tests__/fix.test.js.map +1 -1
- package/dist/__tests__/onboard-preservation.test.js +0 -5
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/optimize.test.js +0 -2
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/repo-picker.test.js +1 -7
- package/dist/__tests__/repo-picker.test.js.map +1 -1
- package/dist/__tests__/review-comment-body.test.js +0 -35
- package/dist/__tests__/review-comment-body.test.js.map +1 -1
- package/dist/__tests__/review-models.test.js +3 -19
- package/dist/__tests__/review-models.test.js.map +1 -1
- package/dist/__tests__/runner.test.js +1 -29
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/cli.js +0 -29
- package/dist/cli.js.map +1 -1
- package/dist/commands/onboard.d.ts +0 -11
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +2 -88
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +6 -65
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +3 -23
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +1 -53
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +6 -52
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/loader.d.ts +1 -3
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +0 -13
- package/dist/config/loader.js.map +1 -1
- package/dist/config/review-model-tiers.json +3 -3
- package/dist/config/schema.d.ts +10 -254
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +2 -62
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +1 -6
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +7 -15
- package/dist/github/client.js.map +1 -1
- package/dist/issues/ticket-ref.d.ts.map +1 -1
- package/dist/issues/ticket-ref.js +5 -6
- package/dist/issues/ticket-ref.js.map +1 -1
- package/dist/lib/clone.d.ts +0 -1
- package/dist/lib/clone.d.ts.map +1 -1
- package/dist/lib/clone.js +10 -32
- package/dist/lib/clone.js.map +1 -1
- package/dist/lib/comment-bodies.d.ts +0 -35
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +9 -43
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/repo-picker.d.ts +0 -3
- package/dist/lib/repo-picker.d.ts.map +1 -1
- package/dist/lib/repo-picker.js +9 -45
- package/dist/lib/repo-picker.js.map +1 -1
- package/dist/lib/review-models.d.ts +2 -15
- package/dist/lib/review-models.d.ts.map +1 -1
- package/dist/lib/review-models.js +6 -26
- package/dist/lib/review-models.js.map +1 -1
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +42 -186
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/workflow.d.ts +0 -9
- package/dist/lib/workflow.d.ts.map +1 -1
- package/dist/lib/workflow.js +0 -20
- package/dist/lib/workflow.js.map +1 -1
- package/dist/reviewers/claude.d.ts +1 -4
- package/dist/reviewers/claude.d.ts.map +1 -1
- package/dist/reviewers/claude.js +7 -39
- package/dist/reviewers/claude.js.map +1 -1
- package/dist/reviewers/codex.d.ts +1 -3
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +70 -76
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/conflict-resolve.d.ts +1 -3
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
- package/dist/reviewers/conflict-resolve.js +6 -21
- package/dist/reviewers/conflict-resolve.js.map +1 -1
- package/dist/reviewers/fix.d.ts +2 -5
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +10 -26
- package/dist/reviewers/fix.js.map +1 -1
- package/get-started.md +4 -139
- package/package.json +3 -4
- package/assets/icon-256.png +0 -0
- package/assets/linear-comment.svg +0 -18
- package/assets/linear-onboard.svg +0 -30
- package/assets/linear-status.svg +0 -23
- package/assets/linear-test.svg +0 -34
- package/assets/skills/code-review/.crosscheck-skill.json +0 -9
- package/assets/skills/code-review/LICENSE +0 -21
- package/assets/skills/code-review/SKILL.md +0 -89
- package/assets/skills/code-review/agents/openai.yaml +0 -3
- package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
- package/assets/skills/code-review-skill/LICENSE +0 -21
- package/assets/skills/code-review-skill/SKILL.md +0 -231
- package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
- package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
- package/assets/skills/code-review-skill/reference/angular.md +0 -768
- package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
- package/assets/skills/code-review-skill/reference/c.md +0 -890
- package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
- package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
- package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
- package/assets/skills/code-review-skill/reference/cpp.md +0 -893
- package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
- package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
- package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
- package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
- package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
- package/assets/skills/code-review-skill/reference/csharp.md +0 -525
- package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
- package/assets/skills/code-review-skill/reference/django.md +0 -985
- package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
- package/assets/skills/code-review-skill/reference/go.md +0 -993
- package/assets/skills/code-review-skill/reference/java.md +0 -409
- package/assets/skills/code-review-skill/reference/java8.md +0 -586
- package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
- package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
- package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
- package/assets/skills/code-review-skill/reference/php.md +0 -684
- package/assets/skills/code-review-skill/reference/python.md +0 -1073
- package/assets/skills/code-review-skill/reference/qt.md +0 -757
- package/assets/skills/code-review-skill/reference/react.md +0 -871
- package/assets/skills/code-review-skill/reference/ruby.md +0 -964
- package/assets/skills/code-review-skill/reference/rust.md +0 -846
- package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
- package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
- package/assets/skills/code-review-skill/reference/swift.md +0 -936
- package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
- package/assets/skills/code-review-skill/reference/vue.md +0 -924
- package/assets/skills/code-review-skill/reference/zig.md +0 -440
- package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
- package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
- package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
- package/assets/skills/codebase-design/DEEPENING.md +0 -37
- package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
- package/assets/skills/codebase-design/LICENSE +0 -21
- package/assets/skills/codebase-design/SKILL.md +0 -114
- package/assets/skills/codebase-design/agents/openai.yaml +0 -3
- package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
- package/assets/skills/diagnosing-bugs/LICENSE +0 -21
- package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
- package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
- package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
- package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
- package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
- package/dist/__tests__/can-write-verdict.test.js +0 -31
- package/dist/__tests__/can-write-verdict.test.js.map +0 -1
- package/dist/__tests__/linear-branding.test.d.ts +0 -2
- package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
- package/dist/__tests__/linear-branding.test.js +0 -156
- package/dist/__tests__/linear-branding.test.js.map +0 -1
- package/dist/__tests__/linear-client.test.d.ts +0 -2
- package/dist/__tests__/linear-client.test.d.ts.map +0 -1
- package/dist/__tests__/linear-client.test.js +0 -120
- package/dist/__tests__/linear-client.test.js.map +0 -1
- package/dist/__tests__/linear-comment.test.d.ts +0 -2
- package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
- package/dist/__tests__/linear-comment.test.js +0 -151
- package/dist/__tests__/linear-comment.test.js.map +0 -1
- package/dist/__tests__/linear-identity.test.d.ts +0 -2
- package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
- package/dist/__tests__/linear-identity.test.js +0 -253
- package/dist/__tests__/linear-identity.test.js.map +0 -1
- package/dist/__tests__/linear-notify.test.d.ts +0 -2
- package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
- package/dist/__tests__/linear-notify.test.js +0 -144
- package/dist/__tests__/linear-notify.test.js.map +0 -1
- package/dist/__tests__/linear-ref.test.d.ts +0 -2
- package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
- package/dist/__tests__/linear-ref.test.js +0 -261
- package/dist/__tests__/linear-ref.test.js.map +0 -1
- package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
- package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
- package/dist/__tests__/linear-test-ref.test.js +0 -81
- package/dist/__tests__/linear-test-ref.test.js.map +0 -1
- package/dist/__tests__/linear-verify.test.d.ts +0 -2
- package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
- package/dist/__tests__/linear-verify.test.js +0 -132
- package/dist/__tests__/linear-verify.test.js.map +0 -1
- package/dist/__tests__/linear-worker.test.d.ts +0 -2
- package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
- package/dist/__tests__/linear-worker.test.js +0 -83
- package/dist/__tests__/linear-worker.test.js.map +0 -1
- package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
- package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
- package/dist/__tests__/linear-write-possible.test.js +0 -30
- package/dist/__tests__/linear-write-possible.test.js.map +0 -1
- package/dist/__tests__/repository-guidance.test.d.ts +0 -2
- package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
- package/dist/__tests__/repository-guidance.test.js +0 -107
- package/dist/__tests__/repository-guidance.test.js.map +0 -1
- package/dist/__tests__/review-strategy.test.d.ts +0 -2
- package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
- package/dist/__tests__/review-strategy.test.js +0 -195
- package/dist/__tests__/review-strategy.test.js.map +0 -1
- package/dist/__tests__/skill-attribution.test.d.ts +0 -2
- package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
- package/dist/__tests__/skill-attribution.test.js +0 -53
- package/dist/__tests__/skill-attribution.test.js.map +0 -1
- package/dist/__tests__/skill-broker.test.d.ts +0 -2
- package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
- package/dist/__tests__/skill-broker.test.js +0 -144
- package/dist/__tests__/skill-broker.test.js.map +0 -1
- package/dist/__tests__/skill-catalog.test.d.ts +0 -2
- package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
- package/dist/__tests__/skill-catalog.test.js +0 -40
- package/dist/__tests__/skill-catalog.test.js.map +0 -1
- package/dist/__tests__/skill-installer.test.d.ts +0 -2
- package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
- package/dist/__tests__/skill-installer.test.js +0 -96
- package/dist/__tests__/skill-installer.test.js.map +0 -1
- package/dist/__tests__/skills-config.test.d.ts +0 -2
- package/dist/__tests__/skills-config.test.d.ts.map +0 -1
- package/dist/__tests__/skills-config.test.js +0 -12
- package/dist/__tests__/skills-config.test.js.map +0 -1
- package/dist/commands/linear-test.d.ts +0 -18
- package/dist/commands/linear-test.d.ts.map +0 -1
- package/dist/commands/linear-test.js +0 -130
- package/dist/commands/linear-test.js.map +0 -1
- package/dist/commands/skill.d.ts +0 -2
- package/dist/commands/skill.d.ts.map +0 -1
- package/dist/commands/skill.js +0 -16
- package/dist/commands/skill.js.map +0 -1
- package/dist/config/review-strategy.json +0 -202
- package/dist/lib/repository-guidance.d.ts +0 -2
- package/dist/lib/repository-guidance.d.ts.map +0 -1
- package/dist/lib/repository-guidance.js +0 -55
- package/dist/lib/repository-guidance.js.map +0 -1
- package/dist/lib/review-strategy.d.ts +0 -62
- package/dist/lib/review-strategy.d.ts.map +0 -1
- package/dist/lib/review-strategy.js +0 -235
- package/dist/lib/review-strategy.js.map +0 -1
- package/dist/linear/client.d.ts +0 -18
- package/dist/linear/client.d.ts.map +0 -1
- package/dist/linear/client.js +0 -67
- package/dist/linear/client.js.map +0 -1
- package/dist/linear/comment.d.ts +0 -20
- package/dist/linear/comment.d.ts.map +0 -1
- package/dist/linear/comment.js +0 -57
- package/dist/linear/comment.js.map +0 -1
- package/dist/linear/identity.d.ts +0 -59
- package/dist/linear/identity.d.ts.map +0 -1
- package/dist/linear/identity.js +0 -187
- package/dist/linear/identity.js.map +0 -1
- package/dist/linear/notify.d.ts +0 -35
- package/dist/linear/notify.d.ts.map +0 -1
- package/dist/linear/notify.js +0 -76
- package/dist/linear/notify.js.map +0 -1
- package/dist/linear/ref.d.ts +0 -13
- package/dist/linear/ref.d.ts.map +0 -1
- package/dist/linear/ref.js +0 -90
- package/dist/linear/ref.js.map +0 -1
- package/dist/linear/verify.d.ts +0 -26
- package/dist/linear/verify.d.ts.map +0 -1
- package/dist/linear/verify.js +0 -67
- package/dist/linear/verify.js.map +0 -1
- package/dist/skills/attribution.d.ts +0 -4
- package/dist/skills/attribution.d.ts.map +0 -1
- package/dist/skills/attribution.js +0 -14
- package/dist/skills/attribution.js.map +0 -1
- package/dist/skills/broker-server.d.ts +0 -2
- package/dist/skills/broker-server.d.ts.map +0 -1
- package/dist/skills/broker-server.js +0 -17
- package/dist/skills/broker-server.js.map +0 -1
- package/dist/skills/broker.d.ts +0 -42
- package/dist/skills/broker.d.ts.map +0 -1
- package/dist/skills/broker.js +0 -285
- package/dist/skills/broker.js.map +0 -1
- package/dist/skills/catalog.d.ts +0 -28
- package/dist/skills/catalog.d.ts.map +0 -1
- package/dist/skills/catalog.js +0 -104
- package/dist/skills/catalog.js.map +0 -1
- package/dist/skills/installer.d.ts +0 -10
- package/dist/skills/installer.d.ts.map +0 -1
- package/dist/skills/installer.js +0 -138
- package/dist/skills/installer.js.map +0 -1
- package/dist/skills/integrity.d.ts +0 -4
- package/dist/skills/integrity.d.ts.map +0 -1
- package/dist/skills/integrity.js +0 -36
- package/dist/skills/integrity.js.map +0 -1
- package/docs/dynamic-thoroughness.md +0 -286
- package/docs/linear-identity-contract.md +0 -139
- package/docs/linear-identity.md +0 -293
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { buildLinearCommentBody, shouldPostToLinear } from '../linear/comment.js';
|
|
3
|
-
import { parseAnnotation } from '../lib/annotation.js';
|
|
4
|
-
const BASE = {
|
|
5
|
-
signature: '๐ค crosscheck ยท crosscheck',
|
|
6
|
-
verdict: 'NEEDS_WORK',
|
|
7
|
-
reviewer: 'codex',
|
|
8
|
-
origin: 'claude',
|
|
9
|
-
model: 'gpt-5',
|
|
10
|
-
prUrl: 'https://github.com/acme/app/pull/12',
|
|
11
|
-
prTitle: 'feat: add widget',
|
|
12
|
-
sha: 'abc1234',
|
|
13
|
-
};
|
|
14
|
-
describe('buildLinearCommentBody', () => {
|
|
15
|
-
it('puts the signature on the first line', () => {
|
|
16
|
-
// IN-2260 step 3 requires the signature to lead every Linear write.
|
|
17
|
-
const body = buildLinearCommentBody(BASE);
|
|
18
|
-
expect(body.split('\n')[0]).toBe('๐ค crosscheck ยท crosscheck');
|
|
19
|
-
});
|
|
20
|
-
it('states the verdict and links back to the PR', () => {
|
|
21
|
-
const body = buildLinearCommentBody(BASE);
|
|
22
|
-
expect(body).toContain('NEEDS_WORK');
|
|
23
|
-
expect(body).toContain('[feat: add widget](https://github.com/acme/app/pull/12)');
|
|
24
|
-
expect(body).toContain('codex');
|
|
25
|
-
});
|
|
26
|
-
it('embeds a parseable crosscheck annotation', () => {
|
|
27
|
-
const parsed = parseAnnotation(buildLinearCommentBody(BASE));
|
|
28
|
-
expect(parsed).toMatchObject({
|
|
29
|
-
origin: 'claude',
|
|
30
|
-
reviewer: 'codex',
|
|
31
|
-
model: 'gpt-5',
|
|
32
|
-
verdict: 'NEEDS_WORK',
|
|
33
|
-
type: 'review',
|
|
34
|
-
service: 'crosscheck',
|
|
35
|
-
sha: 'abc1234',
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
it('includes the summary when provided', () => {
|
|
39
|
-
const body = buildLinearCommentBody({ ...BASE, summary: 'Two blocking issues in auth.ts' });
|
|
40
|
-
expect(body).toContain('Two blocking issues in auth.ts');
|
|
41
|
-
});
|
|
42
|
-
it('omits the summary section when absent', () => {
|
|
43
|
-
const body = buildLinearCommentBody(BASE);
|
|
44
|
-
expect(body).not.toContain('undefined');
|
|
45
|
-
});
|
|
46
|
-
it('renders UNKNOWN for a null verdict', () => {
|
|
47
|
-
const body = buildLinearCommentBody({ ...BASE, verdict: null });
|
|
48
|
-
expect(body).toContain('UNKNOWN');
|
|
49
|
-
expect(parseAnnotation(body)?.verdict).toBe('UNKNOWN');
|
|
50
|
-
});
|
|
51
|
-
it('escapes brackets in the PR title so the markdown link survives', () => {
|
|
52
|
-
const body = buildLinearCommentBody({ ...BASE, prTitle: 'feat: handle [x] and [y]' });
|
|
53
|
-
expect(body).toContain('[feat: handle \\[x\\] and \\[y\\]](https://github.com/acme/app/pull/12)');
|
|
54
|
-
});
|
|
55
|
-
it('escapes nothing that would break the annotation parse', () => {
|
|
56
|
-
const body = buildLinearCommentBody({ ...BASE, prTitle: 'feat: add <!-- crosscheck: fake --> widget' });
|
|
57
|
-
// The real annotation is last, so it still wins.
|
|
58
|
-
expect(parseAnnotation(body)?.reviewer).toBe('codex');
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
describe('shouldPostToLinear', () => {
|
|
62
|
-
const DEFAULTS = ['APPROVE', 'NEEDS_WORK', 'BLOCK'];
|
|
63
|
-
it('posts for each configured verdict', () => {
|
|
64
|
-
for (const v of DEFAULTS)
|
|
65
|
-
expect(shouldPostToLinear(v, DEFAULTS)).toBe(true);
|
|
66
|
-
});
|
|
67
|
-
it('skips a verdict that is not configured', () => {
|
|
68
|
-
expect(shouldPostToLinear('APPROVE', ['BLOCK'])).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
it('skips a null verdict by default', () => {
|
|
71
|
-
expect(shouldPostToLinear(null, DEFAULTS)).toBe(false);
|
|
72
|
-
});
|
|
73
|
-
it('posts a null verdict when UNKNOWN is opted in', () => {
|
|
74
|
-
expect(shouldPostToLinear(null, ['BLOCK', 'UNKNOWN'])).toBe(true);
|
|
75
|
-
});
|
|
76
|
-
it('skips everything when the list is empty', () => {
|
|
77
|
-
expect(shouldPostToLinear('BLOCK', [])).toBe(false);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
describe('workflow step metadata', () => {
|
|
81
|
-
// A recheck posted by runWorkflow must not claim to be a round-1 review โ the
|
|
82
|
-
// Linear annotation has to agree with the GitHub one or parsers see two truths.
|
|
83
|
-
it('defaults to a round-1 review', () => {
|
|
84
|
-
const parsed = parseAnnotation(buildLinearCommentBody(BASE));
|
|
85
|
-
expect(parsed).toMatchObject({ type: 'review', round: 1 });
|
|
86
|
-
});
|
|
87
|
-
it('carries an explicit step type', () => {
|
|
88
|
-
const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck' });
|
|
89
|
-
expect(parseAnnotation(body)).toMatchObject({ type: 'recheck' });
|
|
90
|
-
});
|
|
91
|
-
it('carries an explicit round', () => {
|
|
92
|
-
const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck', round: 3 });
|
|
93
|
-
expect(parseAnnotation(body)).toMatchObject({ type: 'recheck', round: 3 });
|
|
94
|
-
});
|
|
95
|
-
it('matches what the GitHub annotation would carry for the same step', () => {
|
|
96
|
-
const body = buildLinearCommentBody({ ...BASE, stepType: 'fix', round: 2 });
|
|
97
|
-
const parsed = parseAnnotation(body);
|
|
98
|
-
expect(parsed?.type).toBe('fix');
|
|
99
|
-
expect(parsed?.round).toBe(2);
|
|
100
|
-
expect(parsed?.sha).toBe(BASE.sha);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('verdict normalisation', () => {
|
|
104
|
-
// parseVerdict yields "NEEDS WORK"; config and the annotation use "NEEDS_WORK".
|
|
105
|
-
// Comparing raw dropped every NEEDS WORK verdict on the default config.
|
|
106
|
-
it('matches the spaced verdict against the underscored filter', () => {
|
|
107
|
-
expect(shouldPostToLinear('NEEDS WORK', ['NEEDS_WORK', 'BLOCK'])).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
it('matches the underscored verdict too', () => {
|
|
110
|
-
expect(shouldPostToLinear('NEEDS_WORK', ['NEEDS_WORK', 'BLOCK'])).toBe(true);
|
|
111
|
-
});
|
|
112
|
-
it('tolerates a spaced filter entry', () => {
|
|
113
|
-
expect(shouldPostToLinear('NEEDS_WORK', ['NEEDS WORK'])).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
it('is case insensitive', () => {
|
|
116
|
-
expect(shouldPostToLinear('needs work', ['NEEDS_WORK'])).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
it('still excludes a verdict that is genuinely not configured', () => {
|
|
119
|
-
expect(shouldPostToLinear('NEEDS WORK', ['BLOCK'])).toBe(false);
|
|
120
|
-
expect(shouldPostToLinear('APPROVE', ['NEEDS_WORK', 'BLOCK'])).toBe(false);
|
|
121
|
-
});
|
|
122
|
-
it('still maps null to UNKNOWN', () => {
|
|
123
|
-
expect(shouldPostToLinear(null, ['UNKNOWN'])).toBe(true);
|
|
124
|
-
expect(shouldPostToLinear(null, ['NEEDS_WORK', 'BLOCK'])).toBe(false);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
describe('the visible line names the step', () => {
|
|
128
|
-
// The annotation carries type=recheck; the human-readable line saying "review"
|
|
129
|
-
// contradicted it two lines above.
|
|
130
|
-
it('says review by default', () => {
|
|
131
|
-
expect(buildLinearCommentBody(BASE)).toContain('review of [');
|
|
132
|
-
});
|
|
133
|
-
it('says recheck for a recheck', () => {
|
|
134
|
-
const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck' });
|
|
135
|
-
expect(body).toContain('recheck of [');
|
|
136
|
-
expect(body).not.toContain(' review of [');
|
|
137
|
-
});
|
|
138
|
-
it('says fix for a fix step', () => {
|
|
139
|
-
expect(buildLinearCommentBody({ ...BASE, stepType: 'fix' })).toContain('fix for [');
|
|
140
|
-
});
|
|
141
|
-
it('says conflict resolution for a conflict-resolve step', () => {
|
|
142
|
-
expect(buildLinearCommentBody({ ...BASE, stepType: 'conflict-resolve' }))
|
|
143
|
-
.toContain('conflict resolution for [');
|
|
144
|
-
});
|
|
145
|
-
it('agrees with the annotation it embeds', () => {
|
|
146
|
-
const body = buildLinearCommentBody({ ...BASE, stepType: 'recheck', round: 2 });
|
|
147
|
-
expect(body).toContain('recheck of [');
|
|
148
|
-
expect(parseAnnotation(body)).toMatchObject({ type: 'recheck', round: 2 });
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
//# sourceMappingURL=linear-comment.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linear-comment.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-comment.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linear-identity.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/linear-identity.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { renderSignature, mintAppToken, normalizeScopes, resolveLinearAuth, isLinearConfigError } from '../linear/identity.js';
|
|
3
|
-
import { LinearConfigSchema } from '../config/schema.js';
|
|
4
|
-
const SECRET = 'super-secret-value';
|
|
5
|
-
const CLIENT_ID = 'client-abc';
|
|
6
|
-
const MINTED = 'minted-app-token';
|
|
7
|
-
function cfg(overrides = {}) {
|
|
8
|
-
return LinearConfigSchema.parse({ enabled: true, ...overrides });
|
|
9
|
-
}
|
|
10
|
-
function okMint() {
|
|
11
|
-
return vi.fn(async () => new Response(JSON.stringify({ access_token: MINTED }), { status: 200 }));
|
|
12
|
-
}
|
|
13
|
-
describe('renderSignature', () => {
|
|
14
|
-
it('expands {actor} and {product}', () => {
|
|
15
|
-
expect(renderSignature('๐ค {actor} ยท {product}', { actor: 'crosscheck', product: 'crosscheck' })).toBe('๐ค crosscheck ยท crosscheck');
|
|
16
|
-
});
|
|
17
|
-
it('expands repeated placeholders', () => {
|
|
18
|
-
expect(renderSignature('{actor}/{actor} on {product}', { actor: 'cc', product: 'p' })).toBe('cc/cc on p');
|
|
19
|
-
});
|
|
20
|
-
it('leaves unknown placeholders untouched', () => {
|
|
21
|
-
expect(renderSignature('{actor} {nope}', { actor: 'cc', product: 'p' })).toBe('cc {nope}');
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
describe('mintAppToken', () => {
|
|
25
|
-
it('posts client_credentials as a form body and returns the access token', async () => {
|
|
26
|
-
const fetchImpl = okMint();
|
|
27
|
-
const token = await mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl });
|
|
28
|
-
expect(token).toBe(MINTED);
|
|
29
|
-
const [url, init] = fetchImpl.mock.calls[0];
|
|
30
|
-
expect(url).toBe('https://api.linear.app/oauth/token');
|
|
31
|
-
expect(init.method).toBe('POST');
|
|
32
|
-
expect(init.headers['Content-Type']).toBe('application/x-www-form-urlencoded');
|
|
33
|
-
// The secret travels in the request body โ never a URL parameter, never argv.
|
|
34
|
-
expect(String(url)).not.toContain(SECRET);
|
|
35
|
-
const body = new URLSearchParams(init.body);
|
|
36
|
-
expect(body.get('grant_type')).toBe('client_credentials');
|
|
37
|
-
expect(body.get('client_id')).toBe(CLIENT_ID);
|
|
38
|
-
expect(body.get('client_secret')).toBe(SECRET);
|
|
39
|
-
expect(body.get('scope')).toBe('read,write');
|
|
40
|
-
});
|
|
41
|
-
it('throws without leaking the secret when the mint is rejected', async () => {
|
|
42
|
-
const fetchImpl = vi.fn(async () => new Response('{"error":"invalid_client"}', { status: 401 }));
|
|
43
|
-
const err = await mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })
|
|
44
|
-
.then(() => null, (e) => e);
|
|
45
|
-
expect(err).toBeInstanceOf(Error);
|
|
46
|
-
expect(err.message).toContain('401');
|
|
47
|
-
expect(err.message).not.toContain(SECRET);
|
|
48
|
-
expect(err.message).not.toContain(CLIENT_ID);
|
|
49
|
-
});
|
|
50
|
-
it('throws when the response has no access_token', async () => {
|
|
51
|
-
const fetchImpl = vi.fn(async () => new Response('{"ok":true}', { status: 200 }));
|
|
52
|
-
await expect(mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })).rejects.toThrow(/no access_token/i);
|
|
53
|
-
});
|
|
54
|
-
it('throws on a non-JSON response', async () => {
|
|
55
|
-
const fetchImpl = vi.fn(async () => new Response('<html>gateway</html>', { status: 200 }));
|
|
56
|
-
await expect(mintAppToken({ clientId: CLIENT_ID, clientSecret: SECRET, scopes: 'read write' }, { fetchImpl })).rejects.toThrow();
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe('resolveLinearAuth โ api_key mode (T0)', () => {
|
|
60
|
-
it('uses the supplied key with a bare Authorization header and no createAsUser', async () => {
|
|
61
|
-
const auth = await resolveLinearAuth(cfg(), { apiKey: 'lin_api_xyz' });
|
|
62
|
-
expect(auth.mode).toBe('api_key');
|
|
63
|
-
expect(auth.token).toBe('lin_api_xyz');
|
|
64
|
-
expect(auth.bearer).toBe(false);
|
|
65
|
-
expect(auth.createAsUser).toBeUndefined();
|
|
66
|
-
expect(auth.signature).toBe('๐ค crosscheck');
|
|
67
|
-
});
|
|
68
|
-
it('honours a configured actor in the signature', async () => {
|
|
69
|
-
const auth = await resolveLinearAuth(cfg({ identity: { actor: 'crosscheck/reviewer' } }), { apiKey: 'k' });
|
|
70
|
-
expect(auth.signature).toBe('๐ค crosscheck/reviewer');
|
|
71
|
-
});
|
|
72
|
-
it('aborts when no key is available, naming the env var to set', async () => {
|
|
73
|
-
await expect(resolveLinearAuth(cfg(), {})).rejects.toThrow(/LINEAR_API_KEY/);
|
|
74
|
-
});
|
|
75
|
-
it('never performs a network call', async () => {
|
|
76
|
-
const fetchImpl = okMint();
|
|
77
|
-
await resolveLinearAuth(cfg(), { apiKey: 'k' }, { fetchImpl });
|
|
78
|
-
expect(fetchImpl).not.toHaveBeenCalled();
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
describe('resolveLinearAuth โ client_credentials mode (T1)', () => {
|
|
82
|
-
const t1 = () => cfg({ auth: { mode: 'client_credentials' }, identity: { actor: 'crosscheck' } });
|
|
83
|
-
it('mints a per-run token and sets createAsUser to the actor', async () => {
|
|
84
|
-
const fetchImpl = okMint();
|
|
85
|
-
const auth = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl });
|
|
86
|
-
expect(auth.mode).toBe('client_credentials');
|
|
87
|
-
expect(auth.token).toBe(MINTED);
|
|
88
|
-
expect(auth.bearer).toBe(true);
|
|
89
|
-
expect(auth.createAsUser).toBe('crosscheck');
|
|
90
|
-
expect(fetchImpl).toHaveBeenCalledTimes(1);
|
|
91
|
-
});
|
|
92
|
-
it('keeps the signature line as T1 fallback text', async () => {
|
|
93
|
-
const auth = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl: okMint() });
|
|
94
|
-
expect(auth.signature).toBe('๐ค crosscheck');
|
|
95
|
-
});
|
|
96
|
-
it('passes the configured scopes through to the mint', async () => {
|
|
97
|
-
const fetchImpl = okMint();
|
|
98
|
-
const config = cfg({ auth: { mode: 'client_credentials', scopes: 'read write initiative:read' } });
|
|
99
|
-
await resolveLinearAuth(config, { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl });
|
|
100
|
-
const [, init] = fetchImpl.mock.calls[0];
|
|
101
|
-
expect(new URLSearchParams(init.body).get('scope')).toBe('read,write,initiative:read');
|
|
102
|
-
});
|
|
103
|
-
describe('abort semantics โ never silently fall back to api_key', () => {
|
|
104
|
-
it('aborts when the mint fails even though an api_key is available', async () => {
|
|
105
|
-
const fetchImpl = vi.fn(async () => new Response('nope', { status: 500 }));
|
|
106
|
-
await expect(resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET, apiKey: 'lin_api_fallback' }, { fetchImpl })).rejects.toThrow(/client_credentials/);
|
|
107
|
-
});
|
|
108
|
-
it('aborts when credentials are missing even though an api_key is available', async () => {
|
|
109
|
-
const fetchImpl = okMint();
|
|
110
|
-
await expect(resolveLinearAuth(t1(), { apiKey: 'lin_api_fallback' }, { fetchImpl })).rejects.toThrow(/LINEAR_CLIENT_ID/);
|
|
111
|
-
expect(fetchImpl).not.toHaveBeenCalled();
|
|
112
|
-
});
|
|
113
|
-
it('names both env vars when only one is set', async () => {
|
|
114
|
-
await expect(resolveLinearAuth(t1(), { clientId: CLIENT_ID }, { fetchImpl: okMint() })).rejects.toThrow(/LINEAR_CLIENT_SECRET/);
|
|
115
|
-
});
|
|
116
|
-
it('does not leak the secret in the abort message', async () => {
|
|
117
|
-
const fetchImpl = vi.fn(async () => new Response('nope', { status: 500 }));
|
|
118
|
-
const err = await resolveLinearAuth(t1(), { clientId: CLIENT_ID, clientSecret: SECRET }, { fetchImpl })
|
|
119
|
-
.then(() => null, (e) => e);
|
|
120
|
-
expect(err.message).not.toContain(SECRET);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
it('respects custom env var names in the abort message', async () => {
|
|
124
|
-
const config = cfg({ auth: { mode: 'client_credentials', client_id_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_ID' } });
|
|
125
|
-
await expect(resolveLinearAuth(config, {})).rejects.toThrow(/LINEAR_HB_AGENT_GATEWAY_CLIENT_ID/);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe('normalizeScopes', () => {
|
|
129
|
-
// Linear documents comma-separated; OAuth 2.0 specifies space-separated. Operators
|
|
130
|
-
// write both, so accept either and always send what Linear asks for.
|
|
131
|
-
it('passes a comma-separated list through', () => {
|
|
132
|
-
expect(normalizeScopes('read,write')).toBe('read,write');
|
|
133
|
-
});
|
|
134
|
-
it('converts a space-separated list', () => {
|
|
135
|
-
expect(normalizeScopes('read write')).toBe('read,write');
|
|
136
|
-
});
|
|
137
|
-
it('handles mixed separators and stray whitespace', () => {
|
|
138
|
-
expect(normalizeScopes(' read, write initiative:read ')).toBe('read,write,initiative:read');
|
|
139
|
-
});
|
|
140
|
-
it('drops empty entries rather than sending blanks', () => {
|
|
141
|
-
expect(normalizeScopes('read,,write,')).toBe('read,write');
|
|
142
|
-
});
|
|
143
|
-
it('returns empty for an empty input', () => {
|
|
144
|
-
expect(normalizeScopes(' ')).toBe('');
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
describe('LinearConfigError โ exit-code classification', () => {
|
|
148
|
-
// The CLI contract reserves exit 2 for unexpected errors; a missing env var is a
|
|
149
|
-
// user error and must be 1, matching what `crosscheck review` already returns.
|
|
150
|
-
it('flags a missing api_key as a config error', async () => {
|
|
151
|
-
const err = await resolveLinearAuth(cfg(), {}).then(() => null, (e) => e);
|
|
152
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
153
|
-
});
|
|
154
|
-
it('flags missing client credentials as a config error', async () => {
|
|
155
|
-
const config = cfg({ auth: { mode: 'client_credentials' } });
|
|
156
|
-
const err = await resolveLinearAuth(config, {}).then(() => null, (e) => e);
|
|
157
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
158
|
-
});
|
|
159
|
-
it('flags a rejected mint as a config error', async () => {
|
|
160
|
-
const fetchImpl = vi.fn(async () => new Response('nope', { status: 401 }));
|
|
161
|
-
const config = cfg({ auth: { mode: 'client_credentials' } });
|
|
162
|
-
const err = await resolveLinearAuth(config, { clientId: 'a', clientSecret: 'b' }, { fetchImpl })
|
|
163
|
-
.then(() => null, (e) => e);
|
|
164
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
165
|
-
});
|
|
166
|
-
it('does not flag unrelated errors', () => {
|
|
167
|
-
expect(isLinearConfigError(new Error('network down'))).toBe(false);
|
|
168
|
-
expect(isLinearConfigError(undefined)).toBe(false);
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
describe('outage vs misconfiguration', () => {
|
|
172
|
-
// A 5xx is Linear's problem, not the operator's โ blaming it on the config
|
|
173
|
-
// would exit 1 and send someone hunting a broken env var that is fine.
|
|
174
|
-
const t1 = () => cfg({ auth: { mode: 'client_credentials' } });
|
|
175
|
-
const creds = { clientId: 'id', clientSecret: 'secret' };
|
|
176
|
-
const status = (code) => vi.fn(async () => new Response('x', { status: code }));
|
|
177
|
-
it('treats a rejected credential (401) as a config error', async () => {
|
|
178
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(401) }).then(() => null, (e) => e);
|
|
179
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
180
|
-
});
|
|
181
|
-
it('treats a bad request (400) as a config error', async () => {
|
|
182
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(400) }).then(() => null, (e) => e);
|
|
183
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
184
|
-
});
|
|
185
|
-
it('does NOT blame the config for a 500', async () => {
|
|
186
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(500) }).then(() => null, (e) => e);
|
|
187
|
-
expect(err).toBeInstanceOf(Error);
|
|
188
|
-
expect(isLinearConfigError(err)).toBe(false);
|
|
189
|
-
});
|
|
190
|
-
it('does NOT blame the config for a 503', async () => {
|
|
191
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(503) }).then(() => null, (e) => e);
|
|
192
|
-
expect(isLinearConfigError(err)).toBe(false);
|
|
193
|
-
});
|
|
194
|
-
it('does NOT blame the config for a transport failure', async () => {
|
|
195
|
-
const fetchImpl = vi.fn(async () => { throw new Error('ECONNRESET'); });
|
|
196
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl }).then(() => null, (e) => e);
|
|
197
|
-
expect(isLinearConfigError(err)).toBe(false);
|
|
198
|
-
});
|
|
199
|
-
it('aborts either way โ never falls back to api_key', async () => {
|
|
200
|
-
for (const code of [401, 500]) {
|
|
201
|
-
const err = await resolveLinearAuth(t1(), { ...creds, apiKey: 'lin_api_fallback' }, { fetchImpl: status(code) })
|
|
202
|
-
.then(() => null, (e) => e);
|
|
203
|
-
expect(err.message).toMatch(/aborting rather than falling back/);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
describe('rate limiting is transient, not misconfiguration', () => {
|
|
208
|
-
const t1 = () => cfg({ auth: { mode: 'client_credentials' } });
|
|
209
|
-
const creds = { clientId: 'id', clientSecret: 'secret' };
|
|
210
|
-
const status = (code) => vi.fn(async () => new Response('x', { status: code }));
|
|
211
|
-
it('does not blame the config for a 429', async () => {
|
|
212
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(429) }).then(() => null, (e) => e);
|
|
213
|
-
expect(isLinearConfigError(err)).toBe(false);
|
|
214
|
-
});
|
|
215
|
-
it('still blames the config for a 403', async () => {
|
|
216
|
-
const err = await resolveLinearAuth(t1(), creds, { fetchImpl: status(403) }).then(() => null, (e) => e);
|
|
217
|
-
expect(isLinearConfigError(err)).toBe(true);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
describe('a rejected mint names the variables to check', () => {
|
|
221
|
-
// A bare "HTTP 401" leaves an operator with custom env names guessing which
|
|
222
|
-
// credential to rotate. Names only โ never values.
|
|
223
|
-
const rejected = () => vi.fn(async () => new Response('nope', { status: 401 }));
|
|
224
|
-
const creds = { clientId: 'the-id', clientSecret: 'the-secret' };
|
|
225
|
-
it('names the default variables', async () => {
|
|
226
|
-
const config = cfg({ auth: { mode: 'client_credentials' } });
|
|
227
|
-
const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
|
|
228
|
-
.then(() => null, (e) => e);
|
|
229
|
-
expect(err.message).toContain('LINEAR_CLIENT_ID');
|
|
230
|
-
expect(err.message).toContain('LINEAR_CLIENT_SECRET');
|
|
231
|
-
});
|
|
232
|
-
it('names custom variables', async () => {
|
|
233
|
-
const config = cfg({
|
|
234
|
-
auth: {
|
|
235
|
-
mode: 'client_credentials',
|
|
236
|
-
client_id_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_ID',
|
|
237
|
-
client_secret_env: 'LINEAR_HB_AGENT_GATEWAY_CLIENT_SECRET',
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
|
|
241
|
-
.then(() => null, (e) => e);
|
|
242
|
-
expect(err.message).toContain('LINEAR_HB_AGENT_GATEWAY_CLIENT_ID');
|
|
243
|
-
expect(err.message).toContain('LINEAR_HB_AGENT_GATEWAY_CLIENT_SECRET');
|
|
244
|
-
});
|
|
245
|
-
it('still never leaks the values', async () => {
|
|
246
|
-
const config = cfg({ auth: { mode: 'client_credentials' } });
|
|
247
|
-
const err = await resolveLinearAuth(config, creds, { fetchImpl: rejected() })
|
|
248
|
-
.then(() => null, (e) => e);
|
|
249
|
-
expect(err.message).not.toContain('the-secret');
|
|
250
|
-
expect(err.message).not.toContain('the-id');
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
//# sourceMappingURL=linear-identity.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linear-identity.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-identity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linear-notify.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/linear-notify.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { notifyLinear, issueBelongsToWorkspace } from '../linear/notify.js';
|
|
3
|
-
import { LinearConfigSchema } from '../config/schema.js';
|
|
4
|
-
const AUTH = {
|
|
5
|
-
mode: 'client_credentials',
|
|
6
|
-
token: 'minted',
|
|
7
|
-
bearer: true,
|
|
8
|
-
actor: 'crosscheck',
|
|
9
|
-
signature: '๐ค crosscheck ยท crosscheck',
|
|
10
|
-
signatureTemplate: '๐ค {actor} ยท {product}',
|
|
11
|
-
product: 'crosscheck',
|
|
12
|
-
createAsUser: 'crosscheck',
|
|
13
|
-
};
|
|
14
|
-
const PR = {
|
|
15
|
-
branch: 'feat/in-2269-identity',
|
|
16
|
-
title: 'feat: tiered Linear identity',
|
|
17
|
-
body: '',
|
|
18
|
-
url: 'https://github.com/acme/app/pull/12',
|
|
19
|
-
sha: 'abc1234',
|
|
20
|
-
};
|
|
21
|
-
const BASE = { auth: AUTH, pr: PR, verdict: 'NEEDS_WORK', reviewer: 'codex', origin: 'claude', model: 'gpt-5' };
|
|
22
|
-
function cfg(overrides = {}) {
|
|
23
|
-
return LinearConfigSchema.parse({ enabled: true, team_keys: ['IN'], ...overrides });
|
|
24
|
-
}
|
|
25
|
-
/** Replies to the issue lookup, then the comment mutation. */
|
|
26
|
-
function scriptedFetch(issueNodes, mutation) {
|
|
27
|
-
let call = 0;
|
|
28
|
-
return vi.fn(async () => {
|
|
29
|
-
call++;
|
|
30
|
-
if (call === 1)
|
|
31
|
-
return new Response(JSON.stringify({ data: { issues: { nodes: issueNodes } } }), { status: 200 });
|
|
32
|
-
return new Response(JSON.stringify({
|
|
33
|
-
data: mutation ?? { commentCreate: { success: true, comment: { id: 'c1', url: 'https://linear.app/x/c1' } } },
|
|
34
|
-
}), { status: 200 });
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
const FOUND = [{ id: 'uuid-1', identifier: 'IN-2269', url: 'https://linear.app/x/issue/IN-2269' }];
|
|
38
|
-
describe('notifyLinear', () => {
|
|
39
|
-
it('posts to the issue referenced by the branch', async () => {
|
|
40
|
-
const fetchImpl = scriptedFetch(FOUND);
|
|
41
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
42
|
-
expect(result).toEqual({ status: 'posted', identifier: 'IN-2269', url: 'https://linear.app/x/c1' });
|
|
43
|
-
});
|
|
44
|
-
it('sends a body that leads with the signature and carries createAsUser', async () => {
|
|
45
|
-
const fetchImpl = scriptedFetch(FOUND);
|
|
46
|
-
await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
47
|
-
const calls = fetchImpl.mock.calls;
|
|
48
|
-
const mutation = JSON.parse(calls[1][1].body);
|
|
49
|
-
expect(mutation.variables.createAsUser).toBe('crosscheck');
|
|
50
|
-
expect(mutation.variables.body.split('\n')[0]).toBe('๐ค crosscheck ยท crosscheck');
|
|
51
|
-
});
|
|
52
|
-
it('skips when the verdict is not in comment_on', async () => {
|
|
53
|
-
const fetchImpl = scriptedFetch(FOUND);
|
|
54
|
-
const result = await notifyLinear({ ...BASE, config: cfg({ comment_on: ['BLOCK'] }) }, { fetchImpl });
|
|
55
|
-
expect(result).toEqual({ status: 'skipped', reason: 'verdict-not-configured' });
|
|
56
|
-
expect(fetchImpl).not.toHaveBeenCalled();
|
|
57
|
-
});
|
|
58
|
-
it('skips when the PR references no Linear issue', async () => {
|
|
59
|
-
const fetchImpl = scriptedFetch(FOUND);
|
|
60
|
-
const pr = { ...PR, branch: 'feat/no-ref', title: 'chore: bump', body: '' };
|
|
61
|
-
const result = await notifyLinear({ ...BASE, pr, config: cfg() }, { fetchImpl });
|
|
62
|
-
expect(result).toEqual({ status: 'skipped', reason: 'no-issue-ref' });
|
|
63
|
-
expect(fetchImpl).not.toHaveBeenCalled();
|
|
64
|
-
});
|
|
65
|
-
it('skips when the referenced issue does not exist', async () => {
|
|
66
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl: scriptedFetch([]) });
|
|
67
|
-
expect(result).toEqual({ status: 'skipped', reason: 'issue-not-found', identifier: 'IN-2269' });
|
|
68
|
-
});
|
|
69
|
-
it('reports failure instead of throwing when the API errors', async () => {
|
|
70
|
-
const fetchImpl = vi.fn(async () => new Response('{}', { status: 500 }));
|
|
71
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
72
|
-
expect(result.status).toBe('failed');
|
|
73
|
-
expect(result.reason).toContain('500');
|
|
74
|
-
});
|
|
75
|
-
it('reports failure when the mutation is rejected', async () => {
|
|
76
|
-
const fetchImpl = scriptedFetch(FOUND, { commentCreate: { success: false, comment: null } });
|
|
77
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
78
|
-
expect(result.status).toBe('failed');
|
|
79
|
-
expect(result.reason).toMatch(/rejected/i);
|
|
80
|
-
});
|
|
81
|
-
it('never leaks the token in a failure reason', async () => {
|
|
82
|
-
const fetchImpl = vi.fn(async () => new Response('{}', { status: 401 }));
|
|
83
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
84
|
-
expect(result.reason).not.toContain('minted');
|
|
85
|
-
});
|
|
86
|
-
it('follows a linear.app URL in the body when no team_keys are configured', async () => {
|
|
87
|
-
const pr = { ...PR, branch: 'feat/nope', title: 'chore', body: 'https://linear.app/x/issue/IN-2269/z' };
|
|
88
|
-
const result = await notifyLinear({ ...BASE, pr, config: cfg({ team_keys: [] }) }, { fetchImpl: scriptedFetch(FOUND) });
|
|
89
|
-
expect(result.status).toBe('posted');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe('workspace mismatch', () => {
|
|
93
|
-
const scoped = (issueUrl) => {
|
|
94
|
-
let call = 0;
|
|
95
|
-
return vi.fn(async () => {
|
|
96
|
-
call++;
|
|
97
|
-
if (call === 1) {
|
|
98
|
-
return new Response(JSON.stringify({
|
|
99
|
-
data: { issues: { nodes: [{ id: 'u1', identifier: 'IN-2269', url: issueUrl }] } },
|
|
100
|
-
}), { status: 200 });
|
|
101
|
-
}
|
|
102
|
-
return new Response(JSON.stringify({
|
|
103
|
-
data: { commentCreate: { success: true, comment: { id: 'c1', url: 'https://linear.app/x/c1' } } },
|
|
104
|
-
}), { status: 200 });
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
const prWithUrl = (url) => ({ ...PR, branch: 'feat/none', title: 'chore', body: url });
|
|
108
|
-
it('posts when the resolved issue is in the URL-named workspace', async () => {
|
|
109
|
-
const fetchImpl = scoped('https://linear.app/acme/issue/IN-2269/slug');
|
|
110
|
-
const result = await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
|
|
111
|
-
expect(result.status).toBe('posted');
|
|
112
|
-
});
|
|
113
|
-
it('skips when the credentials resolve a different workspace', async () => {
|
|
114
|
-
// Same identifier, different workspace โ a real issue, but not the one meant.
|
|
115
|
-
const fetchImpl = scoped('https://linear.app/other-corp/issue/IN-2269/slug');
|
|
116
|
-
const result = await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
|
|
117
|
-
expect(result).toEqual({ status: 'skipped', reason: 'workspace-mismatch', identifier: 'IN-2269' });
|
|
118
|
-
});
|
|
119
|
-
it('does not post the comment when the workspace mismatches', async () => {
|
|
120
|
-
const fetchImpl = scoped('https://linear.app/other-corp/issue/IN-2269/slug');
|
|
121
|
-
await notifyLinear({ ...BASE, pr: prWithUrl('https://linear.app/acme/issue/IN-2269'), config: cfg({ team_keys: [] }) }, { fetchImpl });
|
|
122
|
-
expect(fetchImpl.mock.calls).toHaveLength(1);
|
|
123
|
-
});
|
|
124
|
-
it('does not constrain a bare ref, which names no workspace', async () => {
|
|
125
|
-
const fetchImpl = scoped('https://linear.app/whatever/issue/IN-2269/slug');
|
|
126
|
-
const result = await notifyLinear({ ...BASE, config: cfg() }, { fetchImpl });
|
|
127
|
-
expect(result.status).toBe('posted');
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
describe('issueBelongsToWorkspace', () => {
|
|
131
|
-
it('matches the first path segment', () => {
|
|
132
|
-
expect(issueBelongsToWorkspace('https://linear.app/acme/issue/IN-1', 'acme')).toBe(true);
|
|
133
|
-
});
|
|
134
|
-
it('is case insensitive', () => {
|
|
135
|
-
expect(issueBelongsToWorkspace('https://linear.app/ACME/issue/IN-1', 'acme')).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
it('rejects a different workspace', () => {
|
|
138
|
-
expect(issueBelongsToWorkspace('https://linear.app/other/issue/IN-1', 'acme')).toBe(false);
|
|
139
|
-
});
|
|
140
|
-
it('fails closed on an unparseable URL', () => {
|
|
141
|
-
expect(issueBelongsToWorkspace('not a url', 'acme')).toBe(false);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
//# sourceMappingURL=linear-notify.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linear-notify.test.js","sourceRoot":"","sources":["../../src/__tests__/linear-notify.test.ts"],"names":[],"mappings":"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"}
|