@on-par/factory-core 0.9.27-next.13 → 0.9.27-next.14

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.
Files changed (95) hide show
  1. package/dist/checkers/preview-check.d.ts +24 -0
  2. package/dist/checkers/preview-check.d.ts.map +1 -0
  3. package/dist/checkers/preview-check.js +57 -0
  4. package/dist/checkers/preview-check.js.map +1 -0
  5. package/dist/checkers/preview-evidence.d.ts +26 -0
  6. package/dist/checkers/preview-evidence.d.ts.map +1 -0
  7. package/dist/checkers/preview-evidence.js +57 -0
  8. package/dist/checkers/preview-evidence.js.map +1 -0
  9. package/dist/checkers/preview-pin.d.ts +16 -0
  10. package/dist/checkers/preview-pin.d.ts.map +1 -0
  11. package/dist/checkers/preview-pin.js +47 -0
  12. package/dist/checkers/preview-pin.js.map +1 -0
  13. package/dist/checkers/preview-receipt.d.ts +7 -0
  14. package/dist/checkers/preview-receipt.d.ts.map +1 -0
  15. package/dist/checkers/preview-receipt.js +33 -0
  16. package/dist/checkers/preview-receipt.js.map +1 -0
  17. package/dist/checkers/preview-source-octokit.d.ts +4 -0
  18. package/dist/checkers/preview-source-octokit.d.ts.map +1 -0
  19. package/dist/checkers/preview-source-octokit.js +47 -0
  20. package/dist/checkers/preview-source-octokit.js.map +1 -0
  21. package/dist/checkers/preview-source.d.ts +35 -0
  22. package/dist/checkers/preview-source.d.ts.map +1 -0
  23. package/dist/checkers/preview-source.js +45 -0
  24. package/dist/checkers/preview-source.js.map +1 -0
  25. package/dist/checkers/preview-url-guard.d.ts +5 -0
  26. package/dist/checkers/preview-url-guard.d.ts.map +1 -0
  27. package/dist/checkers/preview-url-guard.js +84 -0
  28. package/dist/checkers/preview-url-guard.js.map +1 -0
  29. package/dist/checkers/preview-wait.d.ts +26 -0
  30. package/dist/checkers/preview-wait.d.ts.map +1 -0
  31. package/dist/checkers/preview-wait.js +43 -0
  32. package/dist/checkers/preview-wait.js.map +1 -0
  33. package/dist/config/example.d.ts.map +1 -1
  34. package/dist/config/example.js +1 -0
  35. package/dist/config/example.js.map +1 -1
  36. package/dist/config/optional-sections.d.ts +22 -0
  37. package/dist/config/optional-sections.d.ts.map +1 -1
  38. package/dist/config/optional-sections.js +7 -1
  39. package/dist/config/optional-sections.js.map +1 -1
  40. package/dist/config/preview-section.d.ts +49 -0
  41. package/dist/config/preview-section.d.ts.map +1 -0
  42. package/dist/config/preview-section.js +72 -0
  43. package/dist/config/preview-section.js.map +1 -0
  44. package/dist/config/repo.d.ts +22 -0
  45. package/dist/config/repo.d.ts.map +1 -1
  46. package/dist/daemon/execution-config.d.ts +22 -0
  47. package/dist/daemon/execution-config.d.ts.map +1 -1
  48. package/dist/daemon/run-runtime.d.ts +22 -0
  49. package/dist/daemon/run-runtime.d.ts.map +1 -1
  50. package/dist/fakes/fake-github.d.ts +18 -0
  51. package/dist/fakes/fake-github.d.ts.map +1 -0
  52. package/dist/fakes/fake-github.js +28 -0
  53. package/dist/fakes/fake-github.js.map +1 -0
  54. package/dist/internal.d.ts +1 -0
  55. package/dist/internal.d.ts.map +1 -1
  56. package/dist/internal.js +1 -0
  57. package/dist/internal.js.map +1 -1
  58. package/dist/phases/ship-preview.d.ts +18 -0
  59. package/dist/phases/ship-preview.d.ts.map +1 -0
  60. package/dist/phases/ship-preview.js +38 -0
  61. package/dist/phases/ship-preview.js.map +1 -0
  62. package/dist/phases/ship.d.ts +6 -1
  63. package/dist/phases/ship.d.ts.map +1 -1
  64. package/dist/phases/ship.js +33 -4
  65. package/dist/phases/ship.js.map +1 -1
  66. package/dist/public-api-keys.d.ts.map +1 -1
  67. package/dist/public-api-keys.js +2 -0
  68. package/dist/public-api-keys.js.map +1 -1
  69. package/dist/review/marked-block.d.ts +6 -0
  70. package/dist/review/marked-block.d.ts.map +1 -0
  71. package/dist/review/marked-block.js +22 -0
  72. package/dist/review/marked-block.js.map +1 -0
  73. package/dist/review/risk-receipt.d.ts.map +1 -1
  74. package/dist/review/risk-receipt.js +2 -19
  75. package/dist/review/risk-receipt.js.map +1 -1
  76. package/dist/run/ci-rework-loop.d.ts +3 -1
  77. package/dist/run/ci-rework-loop.d.ts.map +1 -1
  78. package/dist/run/ci-rework-loop.js +150 -136
  79. package/dist/run/ci-rework-loop.js.map +1 -1
  80. package/dist/run/ci-rework-round.d.ts +41 -0
  81. package/dist/run/ci-rework-round.d.ts.map +1 -0
  82. package/dist/run/ci-rework-round.js +60 -0
  83. package/dist/run/ci-rework-round.js.map +1 -0
  84. package/dist/run/ci-rework-test-helpers.d.ts +35 -0
  85. package/dist/run/ci-rework-test-helpers.d.ts.map +1 -0
  86. package/dist/run/ci-rework-test-helpers.js +120 -0
  87. package/dist/run/ci-rework-test-helpers.js.map +1 -0
  88. package/dist/run/ship-park.d.ts.map +1 -1
  89. package/dist/run/ship-park.js +2 -0
  90. package/dist/run/ship-park.js.map +1 -1
  91. package/dist/testing.d.ts +2 -0
  92. package/dist/testing.d.ts.map +1 -1
  93. package/dist/testing.js +1 -0
  94. package/dist/testing.js.map +1 -1
  95. package/package.json +5 -5
@@ -0,0 +1,24 @@
1
+ import type { PreviewConfig } from '../config/preview-section.js';
2
+ import type { CommandResult, RunCommandOptions } from '../utils/command-runner.js';
3
+ import { type PreviewCheckResult } from './preview-evidence.js';
4
+ import type { PreviewGitHub } from './preview-source.js';
5
+ import { type PreviewPollDeps } from './preview-wait.js';
6
+ export type { PreviewCheckResult } from './preview-evidence.js';
7
+ export { PREVIEW_REWORK_INSTRUCTIONS, previewReworkSummary } from './preview-evidence.js';
8
+ export interface PreviewCheckInput {
9
+ config: PreviewConfig;
10
+ github: PreviewGitHub;
11
+ owner: string;
12
+ repo: string;
13
+ prNumber: number;
14
+ headSha: string;
15
+ worktree: string;
16
+ env?: Record<string, string>;
17
+ logsDir?: string;
18
+ onPgid?: (pgid: number) => void;
19
+ }
20
+ export interface PreviewCheckDeps extends PreviewPollDeps {
21
+ runCommand: (argv: readonly string[], options: RunCommandOptions) => Promise<CommandResult>;
22
+ }
23
+ export declare function runPreviewCheck(input: PreviewCheckInput, deps?: Partial<PreviewCheckDeps>): Promise<PreviewCheckResult>;
24
+ //# sourceMappingURL=preview-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-check.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAIL,KAAK,kBAAkB,EAGxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAgB,KAAK,eAAe,EAAkB,MAAM,mBAAmB,CAAC;AAGvF,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE1F,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,UAAU,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAC7F;AAgBD,wBAAsB,eAAe,CACnC,KAAK,EAAE,iBAAiB,EACxB,IAAI,GAAE,OAAO,CAAC,gBAAgB,CAAM,GACnC,OAAO,CAAC,kBAAkB,CAAC,CAiD7B"}
@@ -0,0 +1,57 @@
1
+ import { lookup } from 'node:dns/promises';
2
+ import { copyPreviewArtifacts, outputTail, writePreviewEvidence, } from './preview-evidence.js';
3
+ import { probePinned, vetPreviewHost } from './preview-pin.js';
4
+ import { maskUrl } from './preview-url-guard.js';
5
+ import { errorMessage, waitForPreview } from './preview-wait.js';
6
+ import { runVerificationCommand } from './run-command.js';
7
+ export { PREVIEW_REWORK_INSTRUCTIONS, previewReworkSummary } from './preview-evidence.js';
8
+ const DEFAULT_DEPS = {
9
+ probe: probePinned,
10
+ resolveHost: async (hostname) => (await lookup(hostname, { all: true })).map((entry) => entry.address),
11
+ runCommand: runVerificationCommand,
12
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
13
+ now: Date.now,
14
+ };
15
+ const recheckHost = (url, d) => vetPreviewHost(url, d.resolveHost).catch((err) => ({
16
+ ok: false,
17
+ reason: `preview host check failed: ${errorMessage(err)}`,
18
+ }));
19
+ export async function runPreviewCheck(input, deps = {}) {
20
+ const d = { ...DEFAULT_DEPS, ...deps };
21
+ const { config, headSha, worktree } = input;
22
+ const started = d.now();
23
+ const finish = (status, url, fields) => writePreviewEvidence({
24
+ status,
25
+ evidence: {
26
+ ...(url ? { url: maskUrl(url) } : {}),
27
+ headSha,
28
+ command: config.command,
29
+ durationMs: d.now() - started,
30
+ artifacts: [],
31
+ ...fields,
32
+ },
33
+ }, input.logsDir);
34
+ const target = { owner: input.owner, repo: input.repo, prNumber: input.prNumber, headSha };
35
+ const wait = await waitForPreview({ config, github: input.github, target }, d, started + config.readyTimeoutSeconds * 1000);
36
+ const readyWaitMs = d.now() - started;
37
+ if (!wait.ready)
38
+ return finish('preview-unavailable', wait.url, { readyWaitMs, reason: wait.reason });
39
+ const recheck = await recheckHost(wait.url, d);
40
+ if (!recheck.ok)
41
+ return finish('preview-unavailable', wait.url, { readyWaitMs, reason: recheck.reason });
42
+ const r = await d.runCommand(config.command, {
43
+ cwd: worktree,
44
+ env: { ...input.env, [config.urlEnv]: wait.url },
45
+ ...(input.onPgid ? { onPgid: input.onPgid } : {}),
46
+ timeoutMs: config.commandTimeoutSeconds * 1000,
47
+ });
48
+ return finish(r.ok ? 'pass' : 'fail', wait.url, {
49
+ readyWaitMs,
50
+ commandMs: d.now() - started - readyWaitMs,
51
+ exitCode: r.exitCode,
52
+ outputTail: outputTail(r.stdout, r.stderr),
53
+ ...copyPreviewArtifacts(worktree, config.artifacts, input.logsDir),
54
+ ...(r.timedOut ? { reason: `preview command timed out after ${config.commandTimeoutSeconds}s` } : {}),
55
+ });
56
+ }
57
+ //# sourceMappingURL=preview-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-check.js","sourceRoot":"","sources":["../../src/checkers/preview-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type PreviewCheckStatus = 'pass' | 'fail' | 'preview-unavailable';
2
+ export interface PreviewCheckEvidence {
3
+ url?: string;
4
+ headSha: string;
5
+ command: string[];
6
+ exitCode?: number;
7
+ readyWaitMs: number;
8
+ commandMs?: number;
9
+ durationMs: number;
10
+ outputTail?: string;
11
+ artifacts: string[];
12
+ artifactsDir?: string;
13
+ reason?: string;
14
+ evidencePath?: string;
15
+ }
16
+ export interface PreviewCheckResult {
17
+ status: PreviewCheckStatus;
18
+ evidence: PreviewCheckEvidence;
19
+ }
20
+ export declare const PREVIEW_REWORK_INSTRUCTIONS = "The PR's deployed preview failed the repo's preview smoke command. Fix the code so the deployed app passes; do not edit the preview config, the smoke command or its tests to make it pass.";
21
+ export declare function writePreviewEvidence(result: PreviewCheckResult, logsDir: string | undefined): PreviewCheckResult;
22
+ export declare function copyPreviewArtifacts(worktree: string, paths: readonly string[], logsDir: string | undefined): Pick<PreviewCheckEvidence, 'artifacts' | 'artifactsDir'>;
23
+ export declare const outputTail: (stdout: string, stderr: string) => string;
24
+ export declare const previewTimings: (e: PreviewCheckEvidence) => string;
25
+ export declare function previewReworkSummary(result: PreviewCheckResult): string;
26
+ //# sourceMappingURL=preview-evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-evidence.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-evidence.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,qBAAqB,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAOD,eAAO,MAAM,2BAA2B,gMACuJ,CAAC;AAEhM,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CAWhH;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,cAAc,CAAC,CAa1D;AAED,eAAO,MAAM,UAAU,WAAY,MAAM,UAAU,MAAM,KAAG,MAGrC,CAAC;AAIxB,eAAO,MAAM,cAAc,MAAO,oBAAoB,KAAG,MACwD,CAAC;AAElH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAYvE"}
@@ -0,0 +1,57 @@
1
+ import { cpSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { stripAnsi } from './command-log.js';
4
+ const TAIL_CHARS = 2000;
5
+ const SUMMARY_TAIL_CHARS = 1500;
6
+ const EVIDENCE_FILE = 'preview-check.json';
7
+ const ARTIFACTS_DIR = 'preview-artifacts';
8
+ export const PREVIEW_REWORK_INSTRUCTIONS = "The PR's deployed preview failed the repo's preview smoke command. Fix the code so the deployed app passes; do not edit the preview config, the smoke command or its tests to make it pass.";
9
+ export function writePreviewEvidence(result, logsDir) {
10
+ if (!logsDir)
11
+ return result;
12
+ try {
13
+ mkdirSync(logsDir, { recursive: true });
14
+ const evidencePath = join(logsDir, EVIDENCE_FILE);
15
+ const evidence = { ...result.evidence, evidencePath };
16
+ writeFileSync(evidencePath, `${JSON.stringify({ status: result.status, evidence }, null, 2)}\n`);
17
+ return { status: result.status, evidence };
18
+ }
19
+ catch {
20
+ return result;
21
+ }
22
+ }
23
+ export function copyPreviewArtifacts(worktree, paths, logsDir) {
24
+ const artifacts = paths.filter((path) => existsSync(join(worktree, path)));
25
+ if (!logsDir || artifacts.length === 0)
26
+ return { artifacts };
27
+ const artifactsDir = join(logsDir, ARTIFACTS_DIR);
28
+ const copied = artifacts.filter((path) => {
29
+ try {
30
+ cpSync(join(worktree, path), join(artifactsDir, path), { recursive: true });
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ });
37
+ return copied.length > 0 ? { artifacts, artifactsDir } : { artifacts };
38
+ }
39
+ export const outputTail = (stdout, stderr) => stripAnsi([stdout.trim(), stderr.trim()].filter((part) => part !== '').join('\n'))
40
+ .trim()
41
+ .slice(-TAIL_CHARS);
42
+ const seconds = (ms) => `${(ms / 1000).toFixed(1)}s`;
43
+ export const previewTimings = (e) => `Ready wait: ${seconds(e.readyWaitMs)}${e.commandMs === undefined ? '' : `; command: ${seconds(e.commandMs)}`}`;
44
+ export function previewReworkSummary(result) {
45
+ const e = result.evidence;
46
+ return [
47
+ `Preview check: ${result.status}`,
48
+ `URL: ${e.url ?? '-'}`,
49
+ `SHA: ${e.headSha}`,
50
+ `Command: ${e.command.join(' ')}`,
51
+ previewTimings(e),
52
+ ...(e.exitCode === undefined ? [] : [`Exit code: ${e.exitCode}`]),
53
+ ...(e.reason ? [`Reason: ${e.reason}`] : []),
54
+ ...(e.outputTail ? ['Output tail:', e.outputTail.slice(-SUMMARY_TAIL_CHARS)] : []),
55
+ ].join('\n');
56
+ }
57
+ //# sourceMappingURL=preview-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-evidence.js","sourceRoot":"","sources":["../../src/checkers/preview-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAwB7C,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAC3C,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAE1C,MAAM,CAAC,MAAM,2BAA2B,GACtC,6LAA6L,CAAC;AAEhM,MAAM,UAAU,oBAAoB,CAAC,MAA0B,EAAE,OAA2B;IAC1F,IAAI,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC;IAC5B,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC;QACtD,aAAa,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACjG,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,KAAwB,EACxB,OAA2B;IAE3B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,MAAc,EAAU,EAAE,CACnE,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KAC/E,IAAI,EAAE;KACN,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;AAExB,MAAM,OAAO,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAErE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAuB,EAAU,EAAE,CAChE,eAAe,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;AAElH,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC1B,OAAO;QACL,kBAAkB,MAAM,CAAC,MAAM,EAAE;QACjC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE;QACtB,QAAQ,CAAC,CAAC,OAAO,EAAE;QACnB,YAAY,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACjC,cAAc,CAAC,CAAC,CAAC;QACjB,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type LookupFunction } from 'node:net';
2
+ export interface PinnedAddress {
3
+ address: string;
4
+ family: 4 | 6;
5
+ }
6
+ export type PreviewHostVet = {
7
+ ok: true;
8
+ pin: PinnedAddress;
9
+ } | {
10
+ ok: false;
11
+ reason: string;
12
+ };
13
+ export declare function vetPreviewHost(url: string, resolveHost: (hostname: string) => Promise<string[]>): Promise<PreviewHostVet>;
14
+ export declare const pinnedLookup: (pin: PinnedAddress) => LookupFunction;
15
+ export declare function probePinned(url: string, pin: PinnedAddress): Promise<number | null>;
16
+ //# sourceMappingURL=preview-pin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-pin.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-pin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAIrD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAM9F,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GACnD,OAAO,CAAC,cAAc,CAAC,CAYzB;AAED,eAAO,MAAM,YAAY,QACjB,aAAa,KAAG,cAIrB,CAAC;AAEJ,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBnF"}
@@ -0,0 +1,47 @@
1
+ import { request as httpRequest } from 'node:http';
2
+ import { request as httpsRequest } from 'node:https';
3
+ import { isIP } from 'node:net';
4
+ import { isPublicAddress, isPublicHttpUrl, maskUrl } from './preview-url-guard.js';
5
+ const PROBE_TIMEOUT_MS = 5000;
6
+ const bareHost = (hostname) => hostname.replace(/^\[(.*)\]$/, '$1');
7
+ export async function vetPreviewHost(url, resolveHost) {
8
+ if (!isPublicHttpUrl(url))
9
+ return { ok: false, reason: `preview URL ${maskUrl(url)} is not a public http(s) host` };
10
+ const { hostname } = new URL(url);
11
+ const host = bareHost(hostname);
12
+ const addresses = isIP(host) === 0 ? await resolveHost(hostname) : [host];
13
+ const blocked = addresses.find((address) => !isPublicAddress(address));
14
+ if (blocked !== undefined) {
15
+ return { ok: false, reason: `preview host ${hostname} resolves to non-public address ${blocked}` };
16
+ }
17
+ const [address] = addresses;
18
+ if (address === undefined)
19
+ return { ok: false, reason: `preview host ${hostname} resolves to no address` };
20
+ return { ok: true, pin: { address, family: isIP(address) === 6 ? 6 : 4 } };
21
+ }
22
+ export const pinnedLookup = (pin) => (_hostname, options, callback) => {
23
+ if (options.all)
24
+ callback(null, [{ address: pin.address, family: pin.family }]);
25
+ else
26
+ callback(null, pin.address, pin.family);
27
+ };
28
+ export function probePinned(url, pin) {
29
+ const target = new URL(url);
30
+ const send = target.protocol === 'https:' ? httpsRequest : httpRequest;
31
+ const host = bareHost(target.hostname);
32
+ const options = {
33
+ agent: false,
34
+ lookup: pinnedLookup(pin),
35
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
36
+ ...(isIP(host) === 0 ? { servername: host } : {}),
37
+ };
38
+ return new Promise((resolve) => {
39
+ const req = send(target, options, (res) => {
40
+ res.resume();
41
+ resolve(res.statusCode ?? null);
42
+ });
43
+ req.on('error', () => resolve(null));
44
+ req.end();
45
+ });
46
+ }
47
+ //# sourceMappingURL=preview-pin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-pin.js","sourceRoot":"","sources":["../../src/checkers/preview-pin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Octokit } from '@octokit/rest';
2
+ import { type PreviewCheckResult } from './preview-evidence.js';
3
+ export declare const PREVIEW_RECEIPT_START = "<!-- factory:preview-receipt v1 -->";
4
+ export declare const PREVIEW_RECEIPT_END = "<!-- /factory:preview-receipt -->";
5
+ export declare function renderPreviewReceipt(result: PreviewCheckResult): string;
6
+ export declare function publishPreviewReceipt(octokit: Octokit, owner: string, repo: string, prNumber: number, result: PreviewCheckResult): Promise<void>;
7
+ //# sourceMappingURL=preview-receipt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-receipt.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-receipt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,eAAO,MAAM,qBAAqB,wCAAwC,CAAC;AAC3E,eAAO,MAAM,mBAAmB,sCAAsC,CAAC;AAEvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAmBvE;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CAMf"}
@@ -0,0 +1,33 @@
1
+ import { upsertMarkedBlock } from '../review/marked-block.js';
2
+ import { previewTimings } from './preview-evidence.js';
3
+ export const PREVIEW_RECEIPT_START = '<!-- factory:preview-receipt v1 -->';
4
+ export const PREVIEW_RECEIPT_END = '<!-- /factory:preview-receipt -->';
5
+ export function renderPreviewReceipt(result) {
6
+ const e = result.evidence;
7
+ return [
8
+ PREVIEW_RECEIPT_START,
9
+ '### Preview check',
10
+ '',
11
+ `**Result: ${result.status}** on \`${e.url ?? '-'}\` at \`${e.headSha.slice(0, 12)}\``,
12
+ '',
13
+ ...(e.command.length > 0 ? [`- Command: \`${e.command.join(' ')}\``] : []),
14
+ `- ${previewTimings(e)}`,
15
+ ...(e.exitCode === undefined ? [] : [`- Exit code: ${e.exitCode}`]),
16
+ ...(e.reason ? [`- Reason: ${e.reason}`] : []),
17
+ ...(e.artifacts.length > 0
18
+ ? [`- Artifacts: ${e.artifacts.join(', ')}${e.artifactsDir ? ' (copied to the run logs)' : ''}`]
19
+ : []),
20
+ '',
21
+ "_Run by the factory against the PR's preview after CI. Regenerated on each SHIP._",
22
+ PREVIEW_RECEIPT_END,
23
+ ].join('\n');
24
+ }
25
+ export async function publishPreviewReceipt(octokit, owner, repo, prNumber, result) {
26
+ const { data } = await octokit.rest.pulls.get({ owner, repo, pull_number: prNumber });
27
+ const markers = { start: PREVIEW_RECEIPT_START, end: PREVIEW_RECEIPT_END };
28
+ const body = upsertMarkedBlock(data.body, renderPreviewReceipt(result), markers);
29
+ if (body === (data.body ?? ''))
30
+ return;
31
+ await octokit.rest.pulls.update({ owner, repo, pull_number: prNumber, body });
32
+ }
33
+ //# sourceMappingURL=preview-receipt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-receipt.js","sourceRoot":"","sources":["../../src/checkers/preview-receipt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAA2B,MAAM,uBAAuB,CAAC;AAEhF,MAAM,CAAC,MAAM,qBAAqB,GAAG,qCAAqC,CAAC;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAEvE,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC1B,OAAO;QACL,qBAAqB;QACrB,mBAAmB;QACnB,EAAE;QACF,aAAa,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC,GAAG,IAAI,GAAG,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI;QACtF,EAAE;QACF,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,KAAK,cAAc,CAAC,CAAC,CAAC,EAAE;QACxB,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACxB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAChG,CAAC,CAAC,EAAE,CAAC;QACP,EAAE;QACF,mFAAmF;QACnF,mBAAmB;KACpB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAgB,EAChB,KAAa,EACb,IAAY,EACZ,QAAgB,EAChB,MAA0B;IAE1B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,mBAAmB,EAAE,CAAC;IAC3E,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACjF,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QAAE,OAAO;IACvC,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Octokit } from '@octokit/rest';
2
+ import type { PreviewGitHub } from './preview-source.js';
3
+ export declare function createOctokitPreviewGitHub(octokit: Octokit): PreviewGitHub;
4
+ //# sourceMappingURL=preview-source-octokit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-source-octokit.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-source-octokit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CA6C1E"}
@@ -0,0 +1,47 @@
1
+ export function createOctokitPreviewGitHub(octokit) {
2
+ return {
3
+ async listDeployments({ owner, repo, headSha }) {
4
+ const data = await octokit.paginate(octokit.rest.repos.listDeployments, {
5
+ owner,
6
+ repo,
7
+ sha: headSha,
8
+ per_page: 100,
9
+ });
10
+ return data.map((d) => ({ id: d.id, environment: d.environment, createdAt: d.created_at }));
11
+ },
12
+ async listDeploymentStatuses({ owner, repo }, deploymentId) {
13
+ const { data } = await octokit.rest.repos.listDeploymentStatuses({
14
+ owner,
15
+ repo,
16
+ deployment_id: deploymentId,
17
+ per_page: 100,
18
+ });
19
+ return data.map((s) => ({
20
+ state: s.state,
21
+ createdAt: s.created_at,
22
+ environmentUrl: s.environment_url,
23
+ targetUrl: s.target_url,
24
+ }));
25
+ },
26
+ async listComments({ owner, repo, prNumber }) {
27
+ const data = await octokit.paginate(octokit.rest.issues.listComments, {
28
+ owner,
29
+ repo,
30
+ issue_number: prNumber,
31
+ per_page: 100,
32
+ });
33
+ return data.map((c) => ({
34
+ body: c.body ?? '',
35
+ author: c.user?.login ?? '',
36
+ authorAssociation: c.author_association,
37
+ createdAt: c.created_at,
38
+ updatedAt: c.updated_at,
39
+ }));
40
+ },
41
+ async headCommitDate({ owner, repo, headSha }) {
42
+ const { data } = await octokit.rest.repos.getCommit({ owner, repo, ref: headSha });
43
+ return data.commit.committer?.date;
44
+ },
45
+ };
46
+ }
47
+ //# sourceMappingURL=preview-source-octokit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-source-octokit.js","sourceRoot":"","sources":["../../src/checkers/preview-source-octokit.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,0BAA0B,CAAC,OAAgB;IACzD,OAAO;QACL,KAAK,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;YAC5C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE;gBACtE,KAAK;gBACL,IAAI;gBACJ,GAAG,EAAE,OAAO;gBACZ,QAAQ,EAAE,GAAG;aACd,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC9F,CAAC;QACD,KAAK,CAAC,sBAAsB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,YAAY;YACxD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC;gBAC/D,KAAK;gBACL,IAAI;gBACJ,aAAa,EAAE,YAAY;gBAC3B,QAAQ,EAAE,GAAG;aACd,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,SAAS,EAAE,CAAC,CAAC,UAAU;gBACvB,cAAc,EAAE,CAAC,CAAC,eAAe;gBACjC,SAAS,EAAE,CAAC,CAAC,UAAU;aACxB,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBACpE,KAAK;gBACL,IAAI;gBACJ,YAAY,EAAE,QAAQ;gBACtB,QAAQ,EAAE,GAAG;aACd,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;gBAClB,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;gBAC3B,iBAAiB,EAAE,CAAC,CAAC,kBAAkB;gBACvC,SAAS,EAAE,CAAC,CAAC,UAAU;gBACvB,SAAS,EAAE,CAAC,CAAC,UAAU;aACxB,CAAC,CAAC,CAAC;QACN,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;YAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YACnF,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC;QACrC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { PreviewConfig } from '../config/preview-section.js';
2
+ export interface PreviewTarget {
3
+ owner: string;
4
+ repo: string;
5
+ prNumber: number;
6
+ headSha: string;
7
+ }
8
+ export interface PreviewDeployment {
9
+ id: number;
10
+ environment: string;
11
+ createdAt: string;
12
+ }
13
+ export interface PreviewDeploymentStatus {
14
+ state: string;
15
+ createdAt: string;
16
+ environmentUrl?: string;
17
+ targetUrl?: string;
18
+ }
19
+ export interface PreviewComment {
20
+ body: string;
21
+ author: string;
22
+ authorAssociation: string;
23
+ createdAt: string;
24
+ updatedAt: string;
25
+ }
26
+ export interface PreviewGitHub {
27
+ listDeployments(target: PreviewTarget): Promise<PreviewDeployment[]>;
28
+ listDeploymentStatuses(target: PreviewTarget, deploymentId: number): Promise<PreviewDeploymentStatus[]>;
29
+ listComments(target: PreviewTarget): Promise<PreviewComment[]>;
30
+ headCommitDate(target: PreviewTarget): Promise<string | undefined>;
31
+ }
32
+ type PreviewSource = PreviewConfig['source'];
33
+ export declare function findPreviewUrl(github: PreviewGitHub, target: PreviewTarget, source: PreviewSource): Promise<string | null>;
34
+ export {};
35
+ //# sourceMappingURL=preview-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-source.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACrE,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAAC;IACxG,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/D,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACpE;AAED,KAAK,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;AAgD7C,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB"}
@@ -0,0 +1,45 @@
1
+ const SHORT_SHA = 7;
2
+ const globToRegExp = (glob) => new RegExp(`^${glob
3
+ .split('*')
4
+ .map((part) => part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'))
5
+ .join('.*')}$`);
6
+ const newestFirst = (items, at) => [...items].sort((a, b) => Date.parse(at(b)) - Date.parse(at(a)));
7
+ async function findDeploymentUrl(github, target, environment) {
8
+ const matches = globToRegExp(environment);
9
+ const deployments = (await github.listDeployments(target)).filter((d) => matches.test(d.environment));
10
+ for (const deployment of newestFirst(deployments, (d) => d.createdAt)) {
11
+ const [newest] = newestFirst(await github.listDeploymentStatuses(target, deployment.id), (s) => s.createdAt);
12
+ if (newest?.state !== 'success')
13
+ continue;
14
+ const url = newest.environmentUrl || newest.targetUrl;
15
+ if (url)
16
+ return url;
17
+ }
18
+ return null;
19
+ }
20
+ const isTrusted = (comment, source) => source.authors.some((login) => login.toLowerCase() === comment.author.toLowerCase()) ||
21
+ source.authorAssociations.some((level) => level === comment.authorAssociation);
22
+ async function findCommentUrl(github, target, source) {
23
+ const pattern = new RegExp(source.urlPattern);
24
+ const trusted = (await github.listComments(target)).filter((c) => isTrusted(c, source));
25
+ let headDate;
26
+ for (const comment of newestFirst(trusted, (c) => c.updatedAt)) {
27
+ const match = pattern.exec(comment.body);
28
+ const url = match?.groups?.url ?? match?.[1];
29
+ if (!url)
30
+ continue;
31
+ if (comment.body.includes(target.headSha.slice(0, SHORT_SHA)))
32
+ return url;
33
+ headDate ??= github.headCommitDate(target);
34
+ const committed = await headDate;
35
+ if (committed !== undefined && Date.parse(comment.updatedAt) > Date.parse(committed))
36
+ return url;
37
+ }
38
+ return null;
39
+ }
40
+ export async function findPreviewUrl(github, target, source) {
41
+ return source.kind === 'deployment'
42
+ ? findDeploymentUrl(github, target, source.environment)
43
+ : findCommentUrl(github, target, source);
44
+ }
45
+ //# sourceMappingURL=preview-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-source.js","sourceRoot":"","sources":["../../src/checkers/preview-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function isPublicAddress(ip: string): boolean;
2
+ export declare function isPublicHost(hostname: string): boolean;
3
+ export declare function isPublicHttpUrl(value: string | null | undefined): value is string;
4
+ export declare function maskUrl(value: string): string;
5
+ //# sourceMappingURL=preview-url-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-url-guard.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-url-guard.ts"],"names":[],"mappings":"AAqDA,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAMnD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQtD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAMjF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK7C"}
@@ -0,0 +1,84 @@
1
+ import { isIP, isIPv4 } from 'node:net';
2
+ const BLOCKED_IPV4 = [
3
+ ['0.0.0.0', 8],
4
+ ['10.0.0.0', 8],
5
+ ['100.64.0.0', 10],
6
+ ['127.0.0.0', 8],
7
+ ['169.254.0.0', 16],
8
+ ['172.16.0.0', 12],
9
+ ['192.0.0.0', 24],
10
+ ['192.168.0.0', 16],
11
+ ['198.18.0.0', 15],
12
+ ['224.0.0.0', 4],
13
+ ['240.0.0.0', 4],
14
+ ];
15
+ const BLOCKED_HOST_SUFFIXES = ['.localhost', '.local', '.internal'];
16
+ const ipv4Number = (ip) => ip.split('.').reduce((n, octet) => n * 256 + Number(octet), 0);
17
+ const inRange = (ip, [base, bits]) => ip >>> (32 - bits) === ipv4Number(base) >>> (32 - bits);
18
+ const isPublicIpv4 = (ip) => !BLOCKED_IPV4.some((range) => inRange(ipv4Number(ip), range));
19
+ function ipv6Words(ip) {
20
+ const lastColon = ip.lastIndexOf(':');
21
+ const tail = ip.slice(lastColon + 1);
22
+ const text = isIPv4(tail)
23
+ ? `${ip.slice(0, lastColon + 1)}${(ipv4Number(tail) >>> 16).toString(16)}:${(ipv4Number(tail) & 0xffff).toString(16)}`
24
+ : ip;
25
+ const [head = '', rest] = text.split('::');
26
+ const before = head === '' ? [] : head.split(':');
27
+ const after = rest === undefined || rest === '' ? [] : rest.split(':');
28
+ const fill = rest === undefined ? [] : Array.from({ length: 8 - before.length - after.length }, () => '0');
29
+ return [...before, ...fill, ...after].map((word) => Number.parseInt(word, 16));
30
+ }
31
+ const embeddedIpv4 = (words) => [words[6] >>> 8, words[6] & 0xff, words[7] >>> 8, words[7] & 0xff].join('.');
32
+ function isPublicIpv6(ip) {
33
+ const words = ipv6Words(ip);
34
+ const zeroUntil = (end) => words.slice(0, end).every((word) => word === 0);
35
+ if ((words[0] & 0xffc0) === 0xfe80)
36
+ return false;
37
+ if ((words[0] & 0xfe00) === 0xfc00)
38
+ return false;
39
+ if ((words[0] & 0xff00) === 0xff00)
40
+ return false;
41
+ const mapped = zeroUntil(5) && words[5] === 0xffff;
42
+ const nat64 = words[0] === 0x64 && words[1] === 0xff9b && words.slice(2, 6).every((word) => word === 0);
43
+ if (zeroUntil(6) || mapped || nat64)
44
+ return isPublicIpv4(embeddedIpv4(words));
45
+ return true;
46
+ }
47
+ export function isPublicAddress(ip) {
48
+ const bare = ip.split('%')[0] ?? '';
49
+ const family = isIP(bare);
50
+ if (family === 4)
51
+ return isPublicIpv4(bare);
52
+ if (family === 6)
53
+ return isPublicIpv6(bare.toLowerCase());
54
+ return false;
55
+ }
56
+ export function isPublicHost(hostname) {
57
+ const host = hostname
58
+ .toLowerCase()
59
+ .replace(/^\[(.*)\]$/, '$1')
60
+ .replace(/\.$/, '');
61
+ if (isIP(host) !== 0)
62
+ return isPublicAddress(host);
63
+ if (host === 'localhost' || BLOCKED_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix)))
64
+ return false;
65
+ return host.includes('.');
66
+ }
67
+ export function isPublicHttpUrl(value) {
68
+ if (!value || !URL.canParse(value))
69
+ return false;
70
+ const url = new URL(value);
71
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
72
+ return false;
73
+ if (url.username !== '' || url.password !== '')
74
+ return false;
75
+ return isPublicHost(url.hostname);
76
+ }
77
+ export function maskUrl(value) {
78
+ if (!URL.canParse(value))
79
+ return '***';
80
+ const url = new URL(value);
81
+ const auth = url.username !== '' || url.password !== '' ? '***@' : '';
82
+ return `${url.protocol}//${auth}${url.host}${url.pathname}${url.search === '' ? '' : '?***'}`;
83
+ }
84
+ //# sourceMappingURL=preview-url-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-url-guard.js","sourceRoot":"","sources":["../../src/checkers/preview-url-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { PreviewConfig } from '../config/preview-section.js';
2
+ import { type PinnedAddress } from './preview-pin.js';
3
+ import { type PreviewGitHub, type PreviewTarget } from './preview-source.js';
4
+ export interface PreviewPollDeps {
5
+ probe: (url: string, pin: PinnedAddress) => Promise<number | null>;
6
+ resolveHost: (hostname: string) => Promise<string[]>;
7
+ sleep: (ms: number) => Promise<void>;
8
+ now: () => number;
9
+ }
10
+ export interface PreviewWaitInput {
11
+ config: PreviewConfig;
12
+ github: PreviewGitHub;
13
+ target: PreviewTarget;
14
+ }
15
+ type PreviewWait = {
16
+ ready: true;
17
+ url: string;
18
+ } | {
19
+ ready: false;
20
+ reason: string;
21
+ url?: string;
22
+ };
23
+ export declare const errorMessage: (err: unknown) => string;
24
+ export declare function waitForPreview({ config, github, target }: PreviewWaitInput, d: PreviewPollDeps, deadline: number): Promise<PreviewWait>;
25
+ export {};
26
+ //# sourceMappingURL=preview-wait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-wait.d.ts","sourceRoot":"","sources":["../../src/checkers/preview-wait.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAkB,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG7F,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrD,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,KAAK,WAAW,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAQjG,eAAO,MAAM,YAAY,QAAS,OAAO,KAAG,MAA4D,CAAC;AAgBzG,wBAAsB,cAAc,CAClC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,gBAAgB,EAC5C,CAAC,EAAE,eAAe,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAiBtB"}