Skip to content

Commit 24f5a59

Browse files
wip v28
1 parent 8389518 commit 24f5a59

2 files changed

Lines changed: 115 additions & 9 deletions

File tree

packages/protocol/server.js

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
* sourceRepo?: string | undefined,
8585
* sourceCommit?: string | undefined,
8686
* sourceRef?: string | undefined,
87+
* sourceBranch?: string | undefined,
8788
* workflowRunId?: string | undefined,
8889
* workflowPath?: string | undefined,
8990
* workflowJobName?: string | undefined,
@@ -220,6 +221,26 @@ export function createAppContext({
220221
return [...new Set((values || []).map((value) => String(value || '').trim()).filter(Boolean))];
221222
}
222223

224+
/**
225+
* @param {RequestBodyShape} body
226+
* @param {{ sourceProvider: string, sourceRepo: string, sourceRef?: string | undefined, sourceCommit?: string | undefined, signerAddress?: string | undefined, operatorNote?: string | undefined }} input
227+
* @returns {string}
228+
*/
229+
function buildRepositoryRevisionDepositContent(body, input) {
230+
const title = String(body.title || '').trim() || `Repository revision deposit: ${input.sourceRepo}`;
231+
return [
232+
'Bitcode repository revision deposit',
233+
`Title: ${title}`,
234+
`Provider: ${input.sourceProvider}`,
235+
`Repository: ${input.sourceRepo}`,
236+
`Branch: ${input.sourceRef || 'unspecified'}`,
237+
`Commit: ${input.sourceCommit || 'unspecified'}`,
238+
`Signer: ${input.signerAddress || 'unspecified'}`,
239+
input.operatorNote ? `Operator note: ${input.operatorNote}` : null,
240+
'Materialization: live VCS repository selection anchored by repository, branch, and commit.'
241+
].filter(Boolean).join('\n');
242+
}
243+
223244
/**
224245
* @param {unknown} principal
225246
* @returns {string | undefined}
@@ -558,8 +579,27 @@ export function createAppContext({
558579
throw error;
559580
}
560581

561-
const rawContent = String(body.content || '').trim();
562582
const operatorNote = String(body.operatorNote || '').trim();
583+
const sourceProvider = String(body.sourceProvider || 'github').trim() || 'github';
584+
const sourceRepo = String(body.sourceRepo || body.repo || '').trim() || authSession?.repo || selectedInventoryEntries[0]?.repo || '';
585+
const sourceRef = String(body.sourceRef || body.sourceBranch || '').trim()
586+
|| authSession?.defaultRef
587+
|| selectedInventoryEntries.find((entry) => entry.ref)?.ref
588+
|| undefined;
589+
const sourceCommit = String(body.sourceCommit || '').trim()
590+
|| selectedInventoryEntries.find((entry) => entry.sourceCommit)?.sourceCommit
591+
|| undefined;
592+
const signerAddress = String(body.signerAddress || '').trim()
593+
|| authSession?.defaultSignerAddress
594+
|| selectedInventoryEntries.find((entry) => entry.signerAddress)?.signerAddress
595+
|| undefined;
596+
const hasRepositoryRevisionSelection = Boolean(
597+
!selectedInventoryEntries.length &&
598+
sourceRepo &&
599+
sourceRef &&
600+
sourceCommit,
601+
);
602+
const rawContent = String(body.content || '').trim();
563603
let content = rawContent;
564604
if (selectedInventoryEntries.length) {
565605
const sections = selectedInventoryEntries.map((entry) => {
@@ -569,6 +609,15 @@ export function createAppContext({
569609
if (operatorNote) sections.push(`Operator note\n${operatorNote}`);
570610
else if (rawContent) sections.push(`Raw fallback supplement\n${rawContent}`);
571611
content = sections.join('\n\n---\n\n');
612+
} else if (!content && hasRepositoryRevisionSelection) {
613+
content = buildRepositoryRevisionDepositContent(body, {
614+
sourceProvider,
615+
sourceRepo,
616+
sourceRef,
617+
sourceCommit,
618+
signerAddress,
619+
operatorNote
620+
});
572621
}
573622
if (!String(content || '').trim()) {
574623
/** @type {StatusError} */
@@ -579,12 +628,13 @@ export function createAppContext({
579628

580629
const inferredKinds = uniqueStrings(selectedInventoryEntries.map((entry) => entry.artifactKind));
581630
const inferredTypes = uniqueStrings(selectedInventoryEntries.map((entry) => entry.artifactType));
582-
const sourceRepo = String(body.sourceRepo || '').trim() || authSession?.repo || selectedInventoryEntries[0]?.repo || 'frontier/demo-auth';
583631
const title = String(body.title || '').trim()
584632
|| (selectedInventoryEntries.length === 1
585633
? (selectedInventoryEntries[0]?.title || '')
586634
: selectedInventoryEntries.length
587635
? `Repo artifact bundle · ${sourceRepo}`
636+
: hasRepositoryRevisionSelection
637+
? `Repository revision deposit · ${sourceRepo}`
588638
: '');
589639
if (!title) {
590640
/** @type {StatusError} */
@@ -610,18 +660,30 @@ export function createAppContext({
610660
title,
611661
author,
612662
organization: body.organization || '$BTD',
613-
artifactKind: String(body.artifactKind || '').trim() || (inferredKinds.length === 1 ? inferredKinds[0] : inferredKinds.length ? 'mixed' : 'mixed'),
614-
artifactType: String(body.artifactType || '').trim() || (inferredTypes.length === 1 ? inferredTypes[0] : undefined),
663+
artifactKind: String(body.artifactKind || '').trim()
664+
|| (inferredKinds.length === 1
665+
? inferredKinds[0]
666+
: inferredKinds.length
667+
? 'mixed'
668+
: hasRepositoryRevisionSelection
669+
? 'repository-revision'
670+
: 'mixed'),
671+
artifactType: String(body.artifactType || '').trim()
672+
|| (inferredTypes.length === 1
673+
? inferredTypes[0]
674+
: hasRepositoryRevisionSelection
675+
? 'vcs-source-anchor'
676+
: undefined),
615677
visualPreview,
616678
operatorNote,
617-
sourceProvider: body.sourceProvider || 'github',
679+
sourceProvider,
618680
sourceRepo,
619-
sourceCommit: String(body.sourceCommit || '').trim() || selectedInventoryEntries.find((entry) => entry.sourceCommit)?.sourceCommit || undefined,
620-
sourceRef: String(body.sourceRef || '').trim() || authSession?.defaultRef || selectedInventoryEntries.find((entry) => entry.ref)?.ref || undefined,
681+
sourceCommit,
682+
sourceRef,
621683
workflowRunId: String(body.workflowRunId || '').trim() || selectedInventoryEntries.find((entry) => entry.workflowRunId)?.workflowRunId || undefined,
622684
workflowPath: String(body.workflowPath || '').trim() || selectedInventoryEntries.find((entry) => entry.workflowPath)?.workflowPath || undefined,
623685
workflowJobName: String(body.workflowJobName || '').trim() || selectedInventoryEntries.find((entry) => entry.workflowJobName)?.workflowJobName || undefined,
624-
signerAddress: String(body.signerAddress || '').trim() || authSession?.defaultSignerAddress || selectedInventoryEntries.find((entry) => entry.signerAddress)?.signerAddress || undefined,
686+
signerAddress,
625687
signingAlgorithm: body.signingAlgorithm || authSession?.signingAlgorithm,
626688
keySource: body.keySource || authSession?.keySource,
627689
installationId: body.installationId || authSession?.installationId,
@@ -632,6 +694,7 @@ export function createAppContext({
632694
inventoryEntries: selectedInventoryEntries,
633695
authSession,
634696
rawFallbackContent: rawContent,
697+
repositoryRevisionManifestUsed: hasRepositoryRevisionSelection && !rawContent,
635698
contentDerivedFromSelection: selectedInventoryEntries.length > 0,
636699
content,
637700
testsPassed: body.testsPassed !== false,

packages/protocol/test/protocol-package-boundary.test.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert from 'node:assert/strict';
2-
import { readdirSync, readFileSync, statSync } from 'node:fs';
2+
import { mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
3+
import { tmpdir } from 'node:os';
34
import path from 'node:path';
45
import { fileURLToPath } from 'node:url';
56
import test from 'node:test';
@@ -47,3 +48,45 @@ test('@bitcode/protocol witness bundle does not overwrite commercial route title
4748
assert.match(appBundle, /data-bitcode-demonstration-witness-host/);
4849
assert.match(appBundle, /if \(shouldUpdateDocumentTitle\(\)\) \{\s*document\.title =/);
4950
});
51+
52+
test('@bitcode/protocol accepts live repository revision deposits without demo inventory ids', async () => {
53+
const protocol = await import('../src/index.js');
54+
const tempDir = mkdtempSync(path.join(tmpdir(), 'bitcode-protocol-repo-deposit-'));
55+
try {
56+
const app = protocol.createAppContext({
57+
dataPath: path.join(tempDir, 'state.json'),
58+
publicDir: path.join(packageRoot, 'public'),
59+
});
60+
61+
const result = app.createDeposit({
62+
title: 'ENGI repository revision',
63+
author: 'engineeredsoftware',
64+
sourceProvider: 'github',
65+
sourceRepo: 'engineeredsoftware/ENGI',
66+
sourceBranch: 'main',
67+
sourceCommit: 'abc123456789',
68+
signerAddress: 'tb1p6x70u8ag7hkmgsve58lxhpgk5fhnanxp2vtuhvccv6n54f2m9mrsxe6wc2',
69+
signingAlgorithm: 'bitcoin_message_signature',
70+
keySource: 'leather-browser-wallet',
71+
walletAuthorizationProof: {
72+
message: 'Bitcode deposit authorization',
73+
signature: 'signed-by-wallet',
74+
provider: 'leather',
75+
},
76+
});
77+
78+
assert.equal(result.ok, true);
79+
assert.equal(result.asset.artifactKind, 'repository-revision');
80+
assert.equal(result.asset.artifactType, 'vcs-source-anchor');
81+
assert.equal(result.asset.addressingSurface.repo, 'engineeredsoftware/ENGI');
82+
assert.equal(result.asset.addressingSurface.ref, 'main');
83+
assert.equal(result.asset.addressingSurface.commit, 'abc123456789');
84+
assert.equal(result.asset.addressingSurface.addressingScope, 'repo-commit');
85+
const depositedText = result.asset.contentUnits?.[0]?.text;
86+
assert.match(depositedText, /Bitcode repository revision deposit/);
87+
assert.match(depositedText, /Repository: engineeredsoftware\/ENGI/);
88+
assert.match(depositedText, /Commit: abc123456789/);
89+
} finally {
90+
rmSync(tempDir, { recursive: true, force: true });
91+
}
92+
});

0 commit comments

Comments
 (0)