noteconnection 1.8.0 → 1.9.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/README.md +257 -1803
- package/dist/src/agent_workspace.contract.parity.test.js +105 -421
- package/dist/src/agent_workspace.frontend.test.js +410 -11
- package/dist/src/android.knowledgebase.picker.contract.test.js +102 -0
- package/dist/src/appimage.patchelf.test.js +113 -0
- package/dist/src/appimage.portability.test.js +156 -0
- package/dist/src/backend/FileLoader.js +18 -4
- package/dist/src/backend/FileLoader.test.js +125 -0
- package/dist/src/backend/GraphBuilder.identity.test.js +86 -0
- package/dist/src/backend/GraphBuilder.js +66 -18
- package/dist/src/backend/GraphBuilder.matching.test.js +127 -0
- package/dist/src/backend/GraphMetrics.js +0 -3
- package/dist/src/backend/ResourceIdentity.js +155 -0
- package/dist/src/backend/ResourceIdentity.test.js +113 -0
- package/dist/src/backend/algorithms/CycleDetection.js +0 -1
- package/dist/src/backend/algorithms/HybridEngine.js +0 -3
- package/dist/src/backend/algorithms/LayoutEngine.js +0 -1
- package/dist/src/backend/algorithms/StatisticalAnalyzer.js +0 -4
- package/dist/src/backend/algorithms/TopologicalSort.js +0 -2
- package/dist/src/backend/build_dag.js +0 -1
- package/dist/src/capacitor.bridge.serialization.contract.test.js +3 -0
- package/dist/src/capacitor.runtime.contract.test.js +11 -2
- package/dist/src/core/Graph.js +138 -42
- package/dist/src/core/Graph.test.js +74 -0
- package/dist/src/core/NoteConnection.js +2 -2
- package/dist/src/core/PathBridge.js +265 -2
- package/dist/src/core/ResourceReference.js +17 -0
- package/dist/src/desktop.godot.pack.test.js +142 -0
- package/dist/src/desktop.runtime.graph.test.js +66 -0
- package/dist/src/export/WorkspaceExportBundle.js +44 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +61 -0
- package/dist/src/foundation.release.evidence.contract.test.js +127 -9
- package/dist/src/foundation.sqlite.runtime.contract.test.js +6 -0
- package/dist/src/frontend/README.md +257 -1803
- package/dist/src/frontend/agent_workspace.js +665 -7
- package/dist/src/frontend/index.html +31 -2
- package/dist/src/frontend/knowledge_projection_contract.js +230 -0
- package/dist/src/frontend/knowledge_projection_store.js +214 -0
- package/dist/src/frontend/libs/path_core.js +158 -42
- package/dist/src/frontend/locales/en.json +32 -0
- package/dist/src/frontend/locales/zh.json +32 -0
- package/dist/src/frontend/mobile_budget_runtime.js +33 -0
- package/dist/src/frontend/mobile_exact_analyzer.js +393 -0
- package/dist/src/frontend/mobile_identity_contract.js +221 -0
- package/dist/src/frontend/mobile_semantic_comparator.js +264 -0
- package/dist/src/frontend/path.html +6 -2
- package/dist/src/frontend/simulationWorker.js +1 -1
- package/dist/src/frontend/source_manager.js +110 -4
- package/dist/src/frontend/storage_provider.js +661 -71
- package/dist/src/frontend/styles.css +107 -13
- package/dist/src/frontend/workspace_panes.js +111 -7
- package/dist/src/frontend.runtime.assets.contract.test.js +81 -0
- package/dist/src/graph.answer.operator.contract.test.js +72 -0
- package/dist/src/index.js +6 -2
- package/dist/src/index.knowledge-root.test.js +118 -0
- package/dist/src/indexing/IndexLifecycle.js +22 -0
- package/dist/src/indexing/IndexLifecycle.test.js +24 -0
- package/dist/src/knowledge.api.contract.test.js +4 -2
- package/dist/src/knowledge_projection.contract.test.js +134 -0
- package/dist/src/knowledge_projection_store.test.js +200 -0
- package/dist/src/learning/AnswerQualityEvaluation.js +153 -0
- package/dist/src/learning/AnswerQualityEvaluation.test.js +118 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +4687 -3892
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +418 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +243 -6
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +25 -1
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +13 -5
- package/dist/src/learning/MeasurementEvidenceConflicts.test.js +78 -0
- package/dist/src/learning/PublicAnswerContract.test.js +85 -0
- package/dist/src/learning/PublicEvidenceSelection.test.js +94 -0
- package/dist/src/learning/PublicMeasurementDisclosure.test.js +54 -0
- package/dist/src/learning/agentConversationExecution.js +211 -0
- package/dist/src/learning/agentConversationExecution.test.js +209 -0
- package/dist/src/learning/agentConversationSerialization.js +266 -0
- package/dist/src/learning/agentConversationSerialization.test.js +165 -0
- package/dist/src/learning/agentResponseBudget.js +179 -0
- package/dist/src/learning/agentResponseBudget.test.js +97 -0
- package/dist/src/learning/agentWorkspaceCapabilityContracts.js +65 -0
- package/dist/src/learning/answerReleaseReview.js +1191 -250
- package/dist/src/learning/answerReleaseReview.test.js +1293 -7
- package/dist/src/learning/answerTaskPlan.js +473 -0
- package/dist/src/learning/conversationComposer.js +627 -386
- package/dist/src/learning/conversationComposer.test.js +1403 -0
- package/dist/src/learning/evidenceContextAssembler.js +312 -120
- package/dist/src/learning/graphAnswerCoverage.js +37 -0
- package/dist/src/learning/graphAnswerCoverage.test.js +93 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.js +59 -0
- package/dist/src/learning/graphAnswerCoverageCalibration.test.js +46 -0
- package/dist/src/learning/graphAnswerFacts.js +94 -0
- package/dist/src/learning/graphAnswerFacts.test.js +39 -0
- package/dist/src/learning/graphAnswerPlan.js +908 -0
- package/dist/src/learning/graphAnswerPlan.test.js +907 -0
- package/dist/src/learning/graphAnswerQualityCalibration.js +255 -0
- package/dist/src/learning/graphAnswerQualityCalibration.test.js +72 -0
- package/dist/src/learning/graphAnswerQualityPolicy.js +30 -0
- package/dist/src/learning/graphClaimMatcher.js +104 -0
- package/dist/src/learning/graphConditionedContext.js +109 -0
- package/dist/src/learning/graphConditionedContext.test.js +99 -0
- package/dist/src/learning/graphContextAssembler.js +3 -13
- package/dist/src/learning/graphContextAssembler.test.js +2 -2
- package/dist/src/learning/graphExpansionPolicy.js +22 -0
- package/dist/src/learning/graphExpansionPolicy.test.js +33 -0
- package/dist/src/learning/identityMetadata.test.js +26 -0
- package/dist/src/learning/index.js +1 -0
- package/dist/src/learning/mobileAnswerProjection.js +104 -0
- package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
- package/dist/src/learning/queryBackend.js +34 -10
- package/dist/src/learning/queryBackend.test.js +21 -0
- package/dist/src/learning/ragContextPack.js +115 -16
- package/dist/src/learning/ragContextPack.test.js +151 -0
- package/dist/src/learning/ragEvidenceQuality.js +96 -0
- package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
- package/dist/src/learning/ragPublicText.js +67 -4
- package/dist/src/learning/ragPublicText.test.js +57 -0
- package/dist/src/learning/ragSufficiencyJudge.js +11 -1
- package/dist/src/learning/ragSufficiencyProviderJudge.js +16 -26
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +51 -0
- package/dist/src/learning/requestNormalization.js +106 -0
- package/dist/src/learning/requestNormalization.test.js +101 -0
- package/dist/src/learning/store.js +116 -12
- package/dist/src/learning/store.test.js +299 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +22 -6
- package/dist/src/learning/vectorAccelerationAdapter.test.js +30 -0
- package/dist/src/learning/workspaceHydration.js +168 -0
- package/dist/src/learning/workspaceHydration.test.js +30 -0
- package/dist/src/license.policy.contract.test.js +9 -4
- package/dist/src/markdown/MarkdownGateway.js +4 -0
- package/dist/src/markdown/MarkdownGateway.test.js +59 -0
- package/dist/src/middleware/SseResponseWriter.js +122 -0
- package/dist/src/middleware/SseResponseWriter.test.js +54 -0
- package/dist/src/middleware/auth.js +28 -7
- package/dist/src/middleware/auth.test.js +33 -0
- package/dist/src/middleware/index.js +2 -1
- package/dist/src/mobile.android.evidence.contract.test.js +146 -0
- package/dist/src/mobile.android.signing.contract.test.js +66 -0
- package/dist/src/mobile.artifact.contract.test.js +144 -0
- package/dist/src/mobile.budget.contract.test.js +90 -0
- package/dist/src/mobile.canonical-id.readiness.test.js +54 -0
- package/dist/src/mobile.graph.parity.contract.test.js +207 -0
- package/dist/src/mobile.identity.contract.test.js +66 -0
- package/dist/src/mobile.identity.corpus.manifest.test.js +72 -0
- package/dist/src/mobile.identity.corpus.test.js +40 -0
- package/dist/src/mobile.native.recovery.contract.test.js +64 -0
- package/dist/src/mobile.pipeline.test.js +11 -1
- package/dist/src/mobile.profile.contract.test.js +225 -0
- package/dist/src/mobile.semantic.parity.test.js +92 -0
- package/dist/src/mobile_exact_analyzer.test.js +113 -0
- package/dist/src/notemd/ContentGenerator.js +4 -9
- package/dist/src/notemd/FileProcessor.js +4 -9
- package/dist/src/notemd/NotemdService.js +12 -17
- package/dist/src/notemd/Translator.js +4 -9
- package/dist/src/notemd/progressReporter.js +9 -0
- package/dist/src/notemd.server.integration.test.js +119 -4
- package/dist/src/notemd.workflow.pipeline.test.js +1 -1
- package/dist/src/pathbridge.handshake.contract.test.js +29 -0
- package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
- package/dist/src/pathcore.bundle.contract.test.js +8 -0
- package/dist/src/platform/ExportProfile.js +28 -0
- package/dist/src/platform/MobileBudget.js +11 -0
- package/dist/src/platform/PlatformCapabilities.js +14 -0
- package/dist/src/platform/PlatformCapabilities.test.js +6 -0
- package/dist/src/query_backend.external_http.integration.test.js +2 -2
- package/dist/src/release.godot.mirror.contract.test.js +28 -4
- package/dist/src/resources/ResourceRegistry.js +40 -0
- package/dist/src/resources/ResourceRegistry.test.js +36 -0
- package/dist/src/routes/index.js +0 -4
- package/dist/src/routes/knowledge.js +46 -33
- package/dist/src/routes/knowledgePayload.js +185 -0
- package/dist/src/routes/knowledgePayload.test.js +53 -0
- package/dist/src/routes/markdown.js +8 -0
- package/dist/src/routes/notemd.js +990 -234
- package/dist/src/routes/registry.contract.test.js +5 -2
- package/dist/src/routes/registry.shadow.contract.test.js +22 -0
- package/dist/src/routes/render.js +14 -51
- package/dist/src/runtime.capabilities.test.js +18 -2
- package/dist/src/server.js +566 -1090
- package/dist/src/server.migration.test.js +417 -15
- package/dist/src/sidecar.build.lock.contract.test.js +201 -0
- package/dist/src/sidecar.freshness.contract.test.js +184 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +6 -3
- package/dist/src/sidecar.supply.readiness.contract.test.js +11 -0
- package/dist/src/simulation.worker.offline.test.js +104 -0
- package/dist/src/storage.provider.capacitor.content.contract.test.js +4 -1
- package/dist/src/storage.provider.contract.test.js +152 -1
- package/dist/src/tauri.frontend.build.contract.test.js +8 -0
- package/dist/src/tauri.window.evidence.execution.test.js +68 -0
- package/dist/src/utils/RuntimePaths.js +6 -0
- package/dist/src/utils/RuntimePaths.test.js +27 -0
- package/dist/src/windows.installer.build.test.js +109 -0
- package/dist/src/windows.installer.payload.test.js +76 -0
- package/dist/src/windows.installer.runtime.test.js +69 -0
- package/dist/src/workspace/WorkspaceRegistry.js +13 -0
- package/package.json +32 -10
- package/dist/src/routes/data.js +0 -267
- package/dist/src/routes/diagnostics.js +0 -51
|
@@ -35,6 +35,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const fs = __importStar(require("fs"));
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
+
const browserTestWindow = {};
|
|
39
|
+
globalThis.window = browserTestWindow;
|
|
40
|
+
const storageProvider = require('./frontend/storage_provider.js');
|
|
38
41
|
describe('storage provider abstraction contract', () => {
|
|
39
42
|
const repoRoot = path.resolve(__dirname, '..');
|
|
40
43
|
const storageProviderPath = path.join(repoRoot, 'src', 'frontend', 'storage_provider.js');
|
|
@@ -43,6 +46,138 @@ describe('storage provider abstraction contract', () => {
|
|
|
43
46
|
expect(source).toContain('window.NoteConnectionStorage = {');
|
|
44
47
|
expect(source).toContain('createProvider');
|
|
45
48
|
expect(source).toContain('class RuntimeStorageProvider');
|
|
49
|
+
expect(source).toContain('getStorageResolution()');
|
|
50
|
+
expect(source).toContain('async refreshStorageResolution()');
|
|
51
|
+
expect(source).toContain("sidecarFetchJson('api/knowledge/store-diagnostics')");
|
|
52
|
+
expect(source).toContain('supportsProjection');
|
|
53
|
+
});
|
|
54
|
+
test('forces projection resolution on Android even when a stale SQLite capability is reported', () => {
|
|
55
|
+
const provider = storageProvider.createProvider({
|
|
56
|
+
runtimeCaps: {
|
|
57
|
+
platform: 'android',
|
|
58
|
+
supports_projection_store: true,
|
|
59
|
+
supports_sqlite: true,
|
|
60
|
+
storage_requested_provider: 'sqlite',
|
|
61
|
+
storage_resolved_provider: 'sqlite',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
expect(provider.getStorageResolution()).toEqual(expect.objectContaining({
|
|
65
|
+
requestedProvider: 'sqlite',
|
|
66
|
+
resolvedProvider: 'projection',
|
|
67
|
+
fallbackReason: 'native_sqlite_runtime_unavailable',
|
|
68
|
+
supportsSqlite: false,
|
|
69
|
+
supportsProjection: true,
|
|
70
|
+
}));
|
|
71
|
+
});
|
|
72
|
+
test('forces projection resolution for an iOS/mobile host without Capacitor globals', () => {
|
|
73
|
+
const provider = storageProvider.createProvider({
|
|
74
|
+
runtimeCaps: {
|
|
75
|
+
platform: 'ios',
|
|
76
|
+
supports_projection_store: true,
|
|
77
|
+
supports_sqlite: true,
|
|
78
|
+
storage_requested_provider: 'sqlite',
|
|
79
|
+
storage_resolved_provider: 'sqlite',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
expect(provider.getStorageResolution()).toEqual(expect.objectContaining({
|
|
83
|
+
requestedProvider: 'sqlite',
|
|
84
|
+
resolvedProvider: 'projection',
|
|
85
|
+
fallbackReason: 'native_sqlite_runtime_unavailable',
|
|
86
|
+
supportsSqlite: false,
|
|
87
|
+
supportsProjection: true,
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
test('keeps SQLite as the desktop default and exposes file fallback explicitly', () => {
|
|
91
|
+
const sqliteProvider = storageProvider.createProvider({
|
|
92
|
+
runtimeCaps: {
|
|
93
|
+
platform: 'win32',
|
|
94
|
+
supports_sidecar: true,
|
|
95
|
+
supports_sqlite: true,
|
|
96
|
+
storage_resolved_provider: 'sqlite',
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
expect(sqliteProvider.getStorageResolution()).toEqual(expect.objectContaining({
|
|
100
|
+
requestedProvider: 'sqlite',
|
|
101
|
+
resolvedProvider: 'sqlite',
|
|
102
|
+
supportsSqlite: true,
|
|
103
|
+
}));
|
|
104
|
+
const fallbackProvider = storageProvider.createProvider({
|
|
105
|
+
runtimeCaps: {
|
|
106
|
+
platform: 'linux',
|
|
107
|
+
supports_sidecar: false,
|
|
108
|
+
supports_sqlite: false,
|
|
109
|
+
storage_requested_provider: 'sqlite',
|
|
110
|
+
storage_resolved_provider: 'file',
|
|
111
|
+
storage_fallback_reason: 'sqlite_runtime_unavailable',
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
expect(fallbackProvider.getStorageResolution()).toEqual(expect.objectContaining({
|
|
115
|
+
requestedProvider: 'sqlite',
|
|
116
|
+
resolvedProvider: 'file',
|
|
117
|
+
fallbackReason: 'sqlite_runtime_unavailable',
|
|
118
|
+
supportsSqlite: false,
|
|
119
|
+
supportsProjection: false,
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
test('does not treat desktop capability support as an active SQLite resolution before diagnostics', () => {
|
|
123
|
+
const provider = storageProvider.createProvider({
|
|
124
|
+
runtimeCaps: {
|
|
125
|
+
platform: 'win32',
|
|
126
|
+
supports_sidecar: true,
|
|
127
|
+
supports_sqlite: true,
|
|
128
|
+
storage_requested_provider: 'sqlite',
|
|
129
|
+
storage_resolved_provider: 'unknown',
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
expect(provider.getStorageResolution()).toEqual(expect.objectContaining({
|
|
133
|
+
requestedProvider: 'sqlite',
|
|
134
|
+
resolvedProvider: undefined,
|
|
135
|
+
supportsSqlite: false,
|
|
136
|
+
}));
|
|
137
|
+
});
|
|
138
|
+
test('refreshes desktop resolution from authoritative sidecar diagnostics', async () => {
|
|
139
|
+
const previousWindow = globalThis.window;
|
|
140
|
+
const previousFetch = globalThis.fetch;
|
|
141
|
+
const runtimeWindow = {
|
|
142
|
+
NoteConnectionRuntime: {
|
|
143
|
+
buildUrl: (resourcePath) => `http://127.0.0.1:3000/${resourcePath}`,
|
|
144
|
+
buildFetchOptions: () => ({ cache: 'no-store' }),
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
globalThis.window = runtimeWindow;
|
|
148
|
+
globalThis.fetch = jest.fn().mockResolvedValue({
|
|
149
|
+
ok: true,
|
|
150
|
+
json: async () => ({
|
|
151
|
+
store: {
|
|
152
|
+
requestedProvider: 'sqlite',
|
|
153
|
+
resolvedProvider: 'file',
|
|
154
|
+
storageEngine: 'file',
|
|
155
|
+
fallbackReason: 'sqlite_runtime_unavailable',
|
|
156
|
+
},
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const provider = storageProvider.createProvider({
|
|
161
|
+
runtimeCaps: {
|
|
162
|
+
platform: 'win32',
|
|
163
|
+
supports_sidecar: true,
|
|
164
|
+
supports_sqlite: true,
|
|
165
|
+
storage_requested_provider: 'sqlite',
|
|
166
|
+
storage_resolved_provider: 'sqlite',
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
await expect(provider.refreshStorageResolution()).resolves.toEqual(expect.objectContaining({
|
|
170
|
+
requestedProvider: 'sqlite',
|
|
171
|
+
resolvedProvider: 'file',
|
|
172
|
+
fallbackReason: 'sqlite_runtime_unavailable',
|
|
173
|
+
supportsSqlite: false,
|
|
174
|
+
}));
|
|
175
|
+
expect(globalThis.fetch).toHaveBeenCalledWith('http://127.0.0.1:3000/api/knowledge/store-diagnostics', { cache: 'no-store' });
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
globalThis.window = previousWindow;
|
|
179
|
+
globalThis.fetch = previousFetch;
|
|
180
|
+
}
|
|
46
181
|
});
|
|
47
182
|
test('supports sidecar, tauri, and read-only capability branches', () => {
|
|
48
183
|
const source = fs.readFileSync(storageProviderPath, 'utf8');
|
|
@@ -53,6 +188,14 @@ describe('storage provider abstraction contract', () => {
|
|
|
53
188
|
expect(source).toContain('getCapacitorFilesystemPlugin()');
|
|
54
189
|
expect(source).toContain('ensureCapacitorFilesystemPermission');
|
|
55
190
|
expect(source).toContain('normalizeCapacitorPath');
|
|
191
|
+
expect(source).toContain('createMobileResourceIdentity');
|
|
192
|
+
expect(source).toContain('canonicalMobileNodeIdFromIdentity');
|
|
193
|
+
expect(source).toContain('NoteConnectionMobileIdentity');
|
|
194
|
+
expect(source).toContain('extractMarkdownLinks');
|
|
195
|
+
expect(source).toContain('sourceUri: file.sourceUri ||');
|
|
196
|
+
expect(source).toContain('canonicalId: file.canonicalId ||');
|
|
197
|
+
expect(source).toContain('identityAliases: Array.isArray(file.identityAliases)');
|
|
198
|
+
expect(source).toContain('Capacitor graph contains duplicate legacy node id');
|
|
56
199
|
expect(source).toContain('extractRelativePathFromKbMarker');
|
|
57
200
|
expect(source).toContain('resolveCapacitorContentCandidatePath');
|
|
58
201
|
expect(source).toContain('async function capacitorReadText(pathValue, options)');
|
|
@@ -64,11 +207,19 @@ describe('storage provider abstraction contract', () => {
|
|
|
64
207
|
expect(source).toContain('CAPACITOR_GRAPH_BUILD_WORKER_TIMEOUT_MS');
|
|
65
208
|
expect(source).toContain("buildMode: 'single-thread-fallback'");
|
|
66
209
|
expect(source).toContain("buildMode: 'worker'");
|
|
210
|
+
expect(source).toContain('var linkedFile = resolveReference(file, rawLink, referenceIndex);');
|
|
211
|
+
expect(source).toContain('addEdge(sourceId, linkedFile && linkedFile.id, "wiki-link")');
|
|
212
|
+
expect(source).toContain('function buildCapacitorReferenceIndex(files)');
|
|
213
|
+
expect(source).toContain('Capacitor graph contains an ambiguous legacy basename');
|
|
214
|
+
expect(source).toContain('sourceUri: sourceNode && sourceNode.sourceUri');
|
|
67
215
|
expect(source).toContain("const result = await capacitorBuildGraph(requestPayload || {}, this.runtimeCaps || {});");
|
|
68
216
|
expect(source).toContain('buildModeDetail: resolveCapacitorBuildModeDetail(buildResult.buildMode, runtimeCaps || {})');
|
|
69
217
|
expect(source).toContain('supportsMobileWasmCompute');
|
|
70
218
|
expect(source).toContain('mobileWasmReason');
|
|
71
219
|
expect(source).toContain("unsupportedOperationError('buildGraph')");
|
|
220
|
+
expect(source).toContain('storage_requested_provider');
|
|
221
|
+
expect(source).toContain('storage_resolved_provider');
|
|
222
|
+
expect(source).toContain('storage_fallback_reason');
|
|
72
223
|
});
|
|
73
224
|
test('defines core storage operations used by source manager and reader', () => {
|
|
74
225
|
const source = fs.readFileSync(storageProviderPath, 'utf8');
|
|
@@ -80,7 +231,7 @@ describe('storage provider abstraction contract', () => {
|
|
|
80
231
|
expect(source).toContain('async buildGraph(requestPayload)');
|
|
81
232
|
expect(source).toContain('async readContent(filePath)');
|
|
82
233
|
expect(source).toContain('const capacitorPath = resolveCapacitorContentCandidatePath(filePath);');
|
|
83
|
-
expect(source).toContain('return await capacitorReadText(capacitorPath
|
|
234
|
+
expect(source).toContain('return await capacitorReadText(capacitorPath, {');
|
|
84
235
|
expect(source).toContain('async setKbPath(kbPath)');
|
|
85
236
|
expect(source).toContain('async readGeneratedAsset(filename)');
|
|
86
237
|
});
|
|
@@ -40,6 +40,7 @@ describe('tauri frontend build contracts', () => {
|
|
|
40
40
|
const packageJsonPath = path.join(repoRoot, 'package.json');
|
|
41
41
|
const tauriConfigPath = path.join(repoRoot, 'src-tauri', 'tauri.conf.json');
|
|
42
42
|
const wrapperScriptPath = path.join(repoRoot, 'scripts', 'run-tauri-frontend-build.js');
|
|
43
|
+
const viteConfigPath = path.join(repoRoot, 'vite.config.ts');
|
|
43
44
|
function readJson(filePath) {
|
|
44
45
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
45
46
|
}
|
|
@@ -57,4 +58,11 @@ describe('tauri frontend build contracts', () => {
|
|
|
57
58
|
expect(wrapper.resolveFrontendBuildCommand({ frontendBuildMode: 'full' })).toBe('npm run build:full');
|
|
58
59
|
expect(() => wrapper.resolveFrontendBuildCommand({ frontendBuildMode: 'legacy-full' })).toThrow(/Unsupported tauri frontend build mode/i);
|
|
59
60
|
});
|
|
61
|
+
test('keeps Vite verification output separate from the Tauri runtime frontend directory', () => {
|
|
62
|
+
const viteConfig = fs.readFileSync(viteConfigPath, 'utf8');
|
|
63
|
+
expect(viteConfig).toContain("const viteVerificationDir = resolve(__dirname, 'dist', 'vite-verify')");
|
|
64
|
+
expect(viteConfig).toContain('outDir: viteVerificationDir');
|
|
65
|
+
expect(viteConfig).toContain('emptyOutDir: true');
|
|
66
|
+
expect(viteConfig).not.toContain('emptyOutDir: false');
|
|
67
|
+
});
|
|
60
68
|
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const child_process_1 = require("child_process");
|
|
4
|
+
jest.mock('child_process', () => ({ ...jest.requireActual('child_process'), spawnSync: jest.fn() }));
|
|
5
|
+
const { runRustWindowEvidenceTests } = require('../scripts/verify-agent-workspace-tauri-window-evidence');
|
|
6
|
+
const { runRustContractTests } = require('../scripts/verify-agent-workspace-tauri-rust');
|
|
7
|
+
const spawn = child_process_1.spawnSync;
|
|
8
|
+
describe('native window test execution evidence', () => {
|
|
9
|
+
afterEach(() => jest.clearAllMocks());
|
|
10
|
+
test.each([
|
|
11
|
+
['empty filter', 'running 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 30 filtered out;\n'],
|
|
12
|
+
['ignored test', 'test tests::{name} ... ignored\n\ntest result: ok. 0 passed; 0 failed; 1 ignored;\n'],
|
|
13
|
+
['different test', 'test tests::some_other_test ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored;\n'],
|
|
14
|
+
['failed test', 'test tests::{name} ... FAILED\n'],
|
|
15
|
+
])('does not qualify a zero-exit Cargo run with %s', (_label, stdout) => {
|
|
16
|
+
spawn.mockImplementation((_command, args) => ({ status: 0, stdout: stdout.replace('{name}', args[3]), stderr: '' }));
|
|
17
|
+
const results = runRustWindowEvidenceTests();
|
|
18
|
+
expect(results).toHaveLength(2);
|
|
19
|
+
expect(results.every((result) => result.passed === false)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
test('requires the named test to pass even when other test executables run zero tests', () => {
|
|
22
|
+
spawn.mockImplementation((_command, args) => ({ status: 0, stderr: '', stdout: `running 0 tests\ntest result: ok. 0 passed; 0 failed;\n\ntest tests::${args[3]} ... ok\n\ntest result: ok. 1 passed; 0 failed;\n` }));
|
|
23
|
+
expect(runRustWindowEvidenceTests().every((result) => result.passed)).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
test('rejects a passing named test when Cargo later fails', () => {
|
|
26
|
+
spawn.mockImplementation((_command, args) => ({ status: 101, stderr: 'later test executable failed', stdout: `test tests::${args[3]} ... ok\n` }));
|
|
27
|
+
expect(runRustWindowEvidenceTests().every((result) => result.passed === false)).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
test('selects the native window feature and library target in separate Cargo processes', () => {
|
|
30
|
+
spawn.mockReturnValue({ status: 0, stdout: '', stderr: '' });
|
|
31
|
+
runRustWindowEvidenceTests();
|
|
32
|
+
expect(spawn).toHaveBeenCalledTimes(2);
|
|
33
|
+
for (const [command, args] of spawn.mock.calls) {
|
|
34
|
+
expect(command).toBe('cargo');
|
|
35
|
+
expect(args).toEqual(expect.arrayContaining(['--lib', '--locked', '--features', 'native-window-tests', '--ignored', '--show-output']));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('ordinary Rust contract execution evidence', () => {
|
|
40
|
+
afterEach(() => jest.clearAllMocks());
|
|
41
|
+
const names = [
|
|
42
|
+
'pathmode_window_toggle_plan_decouples_godot_signal_from_tauri_hide_restore_flags',
|
|
43
|
+
'pathmode_window_toggle_plan_restores_tauri_focus_when_restore_policy_is_enabled',
|
|
44
|
+
'pathmode_window_toggled_event_payload_contains_config_and_execution_plan',
|
|
45
|
+
];
|
|
46
|
+
test.each([
|
|
47
|
+
['empty selection', 0, 'running 0 tests\ntest result: ok. 0 passed; 0 failed;', ''],
|
|
48
|
+
['unrelated passing test', 0, 'test tests::unrelated ... ok', ''],
|
|
49
|
+
['ignored tests', 0, names.map(name => `test tests::${name} ... ignored`).join('\n'), ''],
|
|
50
|
+
['failed Cargo invocation mentioning zero tests', 101, '', '0 tests matched after failure'],
|
|
51
|
+
])('does not qualify %s', (_label, status, stdout, stderr) => {
|
|
52
|
+
spawn.mockReturnValue({ status, stdout, stderr });
|
|
53
|
+
const results = runRustContractTests();
|
|
54
|
+
expect(results.every((result) => result.passed === false)).toBe(true);
|
|
55
|
+
expect(results.every((result) => result.exitCode === status)).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
test('requires every named case, including both toggle policy tests', () => {
|
|
58
|
+
spawn.mockReturnValue({ status: 0, stdout: `test tests::${names[0]} ... ok\n`, stderr: '' });
|
|
59
|
+
expect(runRustContractTests().every((result) => result.passed === false)).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
test('qualifies executed names and preserves a later Cargo failure', () => {
|
|
62
|
+
const stdout = names.map(name => `test tests::${name} ... ok`).join('\n');
|
|
63
|
+
spawn.mockReturnValue({ status: 0, stdout, stderr: '' });
|
|
64
|
+
expect(runRustContractTests().every((result) => result.passed)).toBe(true);
|
|
65
|
+
spawn.mockReturnValue({ status: 101, stdout, stderr: 'process failed' });
|
|
66
|
+
expect(runRustContractTests().every((result) => result.passed === false)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -142,6 +142,11 @@ function resolveRuntimePaths(moduleDir) {
|
|
|
142
142
|
throw new Error(`Unable to provision writable runtime data directory: ${runtimeDataDirCandidate}`);
|
|
143
143
|
}
|
|
144
144
|
const runtimeDataDir = path.resolve(runtimeDataDirCandidate);
|
|
145
|
+
// pkg's projectRoot is a virtual, read-only asset tree. Mutable discovery
|
|
146
|
+
// credentials belong to the writable runtime directory in packaged builds.
|
|
147
|
+
const runtimeManifestPath = process.pkg
|
|
148
|
+
? path.join(runtimeDataDir, 'active-sidecar-runtime.json')
|
|
149
|
+
: path.join(projectRoot, 'tmp', 'active-sidecar-runtime.json');
|
|
145
150
|
const kbCandidates = uniqPaths([
|
|
146
151
|
envKbRoot,
|
|
147
152
|
path.join(projectRoot, 'Knowledge_Base'),
|
|
@@ -154,6 +159,7 @@ function resolveRuntimePaths(moduleDir) {
|
|
|
154
159
|
projectRoot,
|
|
155
160
|
frontendDir,
|
|
156
161
|
runtimeDataDir,
|
|
162
|
+
runtimeManifestPath,
|
|
157
163
|
kbRoot
|
|
158
164
|
};
|
|
159
165
|
}
|
|
@@ -97,6 +97,33 @@ describe('resolveRuntimePaths', () => {
|
|
|
97
97
|
expect(resolved.runtimeDataDir).toBe(path.resolve(runtimeDataDir));
|
|
98
98
|
expect(resolved.kbRoot).toBe(path.resolve(kbRoot));
|
|
99
99
|
});
|
|
100
|
+
test('keeps packaged runtime manifests in the writable runtime directory', () => {
|
|
101
|
+
const previousPkg = Object.getOwnPropertyDescriptor(process, 'pkg');
|
|
102
|
+
Object.defineProperty(process, 'pkg', { configurable: true, value: { entrypoint: '/snapshot/app/server.js' } });
|
|
103
|
+
restoreEnv.push(() => {
|
|
104
|
+
if (previousPkg)
|
|
105
|
+
Object.defineProperty(process, 'pkg', previousPkg);
|
|
106
|
+
else
|
|
107
|
+
Reflect.deleteProperty(process, 'pkg');
|
|
108
|
+
});
|
|
109
|
+
const projectRoot = temp.mkdir('packaged_assets');
|
|
110
|
+
temp.mkdir(path.join('packaged_assets', 'dist', 'src', 'frontend'));
|
|
111
|
+
const runtimeDataDir = temp.mkdir('user_runtime');
|
|
112
|
+
restoreEnv.push(setEnv('NOTE_CONNECTION_PROJECT_ROOT', projectRoot));
|
|
113
|
+
restoreEnv.push(setEnv('NOTE_CONNECTION_RUNTIME_DATA_DIR', runtimeDataDir));
|
|
114
|
+
const resolved = (0, RuntimePaths_1.resolveRuntimePaths)(temp.child('module'));
|
|
115
|
+
expect('runtimeManifestPath' in resolved ? resolved.runtimeManifestPath : undefined)
|
|
116
|
+
.toBe(path.join(runtimeDataDir, 'active-sidecar-runtime.json'));
|
|
117
|
+
});
|
|
118
|
+
test('preserves the development manifest location used by diagnostic tools', () => {
|
|
119
|
+
const projectRoot = temp.mkdir('project');
|
|
120
|
+
temp.mkdir(path.join('project', 'Knowledge_Base'));
|
|
121
|
+
restoreEnv.push(setEnv('NOTE_CONNECTION_PROJECT_ROOT', projectRoot));
|
|
122
|
+
restoreEnv.push(setEnv('NOTE_CONNECTION_RUNTIME_DATA_DIR', temp.mkdir('runtime')));
|
|
123
|
+
const resolved = (0, RuntimePaths_1.resolveRuntimePaths)(temp.child('module'));
|
|
124
|
+
expect('runtimeManifestPath' in resolved ? resolved.runtimeManifestPath : undefined)
|
|
125
|
+
.toBe(path.join(projectRoot, 'tmp', 'active-sidecar-runtime.json'));
|
|
126
|
+
});
|
|
100
127
|
test('normalizes env kb path that points to a folder inside Knowledge_Base', () => {
|
|
101
128
|
const projectRoot = temp.mkdir('project');
|
|
102
129
|
const kbRoot = temp.mkdir(path.join('project', 'Knowledge_Base'));
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const node_child_process_1 = require("node:child_process");
|
|
39
|
+
jest.mock('node:child_process', () => ({ ...jest.requireActual('node:child_process'), spawnSync: jest.fn() }));
|
|
40
|
+
const { recordInstallerBuild, readInstallerBuild } = require('../scripts/verify-windows-installers');
|
|
41
|
+
describe('installer build provenance across fresh runners', () => {
|
|
42
|
+
let directory;
|
|
43
|
+
let receiptPath;
|
|
44
|
+
const environment = { GITHUB_SHA: 'a'.repeat(40), GITHUB_RUN_ID: '123', GITHUB_RUN_ATTEMPT: '1' };
|
|
45
|
+
const write = (relative, contents) => {
|
|
46
|
+
const file = path.join(directory, relative);
|
|
47
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
48
|
+
fs.writeFileSync(file, contents);
|
|
49
|
+
};
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
const temporaryRoot = path.resolve(__dirname, '../output/verification/installer-build-tests');
|
|
52
|
+
fs.mkdirSync(temporaryRoot, { recursive: true });
|
|
53
|
+
directory = fs.mkdtempSync(path.join(temporaryRoot, 'receipt-'));
|
|
54
|
+
receiptPath = path.join(directory, 'output/verification/windows-installer-build.json');
|
|
55
|
+
write('package.json', JSON.stringify({ version: '1.8.0' }));
|
|
56
|
+
write('src/fixture.ts', 'export const source = 1;');
|
|
57
|
+
write('src-tauri/target/release/npm.exe', 'PE __TAURI_BUNDLE_TYPE_VAR_UNK fixture');
|
|
58
|
+
for (const name of ['server', 'godot', 'markdown-worker'])
|
|
59
|
+
write(`src-tauri/bin/${name}-x86_64-pc-windows-msvc.exe`, name);
|
|
60
|
+
write('output/desktop/path_mode.pck', 'GDPC fixture');
|
|
61
|
+
write('src-tauri/target/release/bundle/nsis/NoteConnection_1.8.0_x64-setup.exe', 'NSIS fixture');
|
|
62
|
+
write('src-tauri/target/release/bundle/msi/NoteConnection_1.8.0_x64_en-US.msi', 'MSI fixture');
|
|
63
|
+
recordInstallerBuild(directory, environment);
|
|
64
|
+
});
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
expect(node_child_process_1.spawnSync).not.toHaveBeenCalled();
|
|
67
|
+
jest.clearAllMocks();
|
|
68
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
69
|
+
});
|
|
70
|
+
test.each(['nsis', 'msi'])('accepts %s without build dependencies, including failed-only retries', format => {
|
|
71
|
+
// A qualification runner has only source, the receipt and its installer.
|
|
72
|
+
fs.rmSync(path.join(directory, 'src-tauri/bin'), { recursive: true });
|
|
73
|
+
fs.unlinkSync(path.join(directory, 'src-tauri/target/release/npm.exe'));
|
|
74
|
+
fs.rmSync(path.join(directory, 'output/desktop'), { recursive: true });
|
|
75
|
+
const receipt = readInstallerBuild(format, directory, { ...environment, GITHUB_RUN_ATTEMPT: '2' });
|
|
76
|
+
expect(receipt.buildRunAttempt).toBe('1');
|
|
77
|
+
expect(receipt.expectedFiles[format]).toHaveLength(5);
|
|
78
|
+
expect(readInstallerBuild(format, directory, environment)).toEqual(receipt);
|
|
79
|
+
});
|
|
80
|
+
test.each([
|
|
81
|
+
['sourceRevision', 'b'.repeat(40), /source revision differs/],
|
|
82
|
+
['runId', '456', /workflow run differs/],
|
|
83
|
+
['version', '9.0.0', /version differs/],
|
|
84
|
+
['buildRunAttempt', '0', /build attempt/],
|
|
85
|
+
['buildRunAttempt', '2', /build attempt/],
|
|
86
|
+
['sourceFingerprint', {}, /source fingerprint differs/],
|
|
87
|
+
])('rejects tampered %s before executing anything', (field, replacement, message) => {
|
|
88
|
+
const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
|
|
89
|
+
receipt[field] = replacement;
|
|
90
|
+
fs.writeFileSync(receiptPath, JSON.stringify(receipt));
|
|
91
|
+
expect(() => readInstallerBuild('msi', directory, environment)).toThrow(message);
|
|
92
|
+
});
|
|
93
|
+
test.each(['name', 'path'])('rejects redirected installer %s', field => {
|
|
94
|
+
const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
|
|
95
|
+
receipt.installers.msi[field] = '../other.msi';
|
|
96
|
+
fs.writeFileSync(receiptPath, JSON.stringify(receipt));
|
|
97
|
+
expect(() => readInstallerBuild('msi', directory, environment)).toThrow(/Installer (basename|path) differs/);
|
|
98
|
+
});
|
|
99
|
+
test.each(['MSI altered', 'truncated'])('rejects altered installer bytes (%s)', contents => {
|
|
100
|
+
write('src-tauri/target/release/bundle/msi/NoteConnection_1.8.0_x64_en-US.msi', contents);
|
|
101
|
+
expect(() => readInstallerBuild('msi', directory, environment)).toThrow(/Installer (size|hash) differs/);
|
|
102
|
+
});
|
|
103
|
+
test('rejects changed source and missing receipts without recomputing build expectations', () => {
|
|
104
|
+
write('src/fixture.ts', 'export const source = 2;');
|
|
105
|
+
expect(() => readInstallerBuild('msi', directory, environment)).toThrow(/source fingerprint differs/);
|
|
106
|
+
fs.unlinkSync(receiptPath);
|
|
107
|
+
expect(() => readInstallerBuild('msi', directory, environment)).toThrow(/ENOENT/);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const { verifyInstalledPayload, fingerprintTauriInstallerExecutable } = require('../scripts/verify-windows-installers');
|
|
40
|
+
const { sha256File } = require('../scripts/sidecar-build-fingerprint');
|
|
41
|
+
describe('installed Windows payload verification', () => {
|
|
42
|
+
let directory;
|
|
43
|
+
let expected;
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
directory = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'installed payload '));
|
|
46
|
+
fs.writeFileSync(path.join(directory, 'path_mode.pck'), 'GDPC fixture');
|
|
47
|
+
expected = [{ name: 'path_mode.pck', bytes: 12, sha256: sha256File(path.join(directory, 'path_mode.pck')) }];
|
|
48
|
+
});
|
|
49
|
+
afterEach(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
50
|
+
test('matches exact packaged bytes under paths containing spaces', () => {
|
|
51
|
+
expect(verifyInstalledPayload(directory, expected)).toEqual(expected);
|
|
52
|
+
});
|
|
53
|
+
test('rejects missing resources even when the installer reported success', () => {
|
|
54
|
+
fs.unlinkSync(path.join(directory, 'path_mode.pck'));
|
|
55
|
+
expect(() => verifyInstalledPayload(directory, expected)).toThrow(/missing path_mode.pck/);
|
|
56
|
+
});
|
|
57
|
+
test('rejects same-sized stale resources', () => {
|
|
58
|
+
fs.writeFileSync(path.join(directory, 'path_mode.pck'), 'GDPC altered');
|
|
59
|
+
expect(() => verifyInstalledPayload(directory, expected)).toThrow(/hash differs/);
|
|
60
|
+
});
|
|
61
|
+
test.each(['NSS', 'MSI'])('checks the exact Tauri %s stamp without ignoring executable bytes', (bundleCode) => {
|
|
62
|
+
const executable = path.join(directory, 'build.exe');
|
|
63
|
+
fs.writeFileSync(executable, 'PE before\0__TAURI_BUNDLE_TYPE_VAR_UNK\0PE after');
|
|
64
|
+
const fingerprint = fingerprintTauriInstallerExecutable(executable, bundleCode);
|
|
65
|
+
fs.writeFileSync(path.join(directory, 'npm.exe'), `PE before\0__TAURI_BUNDLE_TYPE_VAR_${bundleCode}\0PE after`);
|
|
66
|
+
expect(verifyInstalledPayload(directory, [fingerprint])).toEqual([fingerprint]);
|
|
67
|
+
fs.writeFileSync(path.join(directory, 'npm.exe'), `PE edited\0__TAURI_BUNDLE_TYPE_VAR_${bundleCode}\0PE after`);
|
|
68
|
+
expect(() => verifyInstalledPayload(directory, [fingerprint])).toThrow(/hash differs/);
|
|
69
|
+
expect(fs.readFileSync(executable, 'utf8')).toContain('_VAR_UNK');
|
|
70
|
+
});
|
|
71
|
+
test.each(['missing marker', '__TAURI_BUNDLE_TYPE_VAR_UNK__TAURI_BUNDLE_TYPE_VAR_UNK'])('rejects missing or ambiguous bundle stamps (%s)', (contents) => {
|
|
72
|
+
const executable = path.join(directory, 'build.exe');
|
|
73
|
+
fs.writeFileSync(executable, contents);
|
|
74
|
+
expect(() => fingerprintTauriInstallerExecutable(executable, 'NSS')).toThrow(/exactly one/);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const os = __importStar(require("node:os"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const node_child_process_1 = require("node:child_process");
|
|
40
|
+
jest.mock('node:child_process', () => ({ ...jest.requireActual('node:child_process'), spawnSync: jest.fn() }));
|
|
41
|
+
const { verifyInstalledRuntime } = require('../scripts/verify-windows-installers');
|
|
42
|
+
const spawn = node_child_process_1.spawnSync;
|
|
43
|
+
describe('installed runtime evidence verdict', () => {
|
|
44
|
+
let directory;
|
|
45
|
+
let run;
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
directory = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'installer-runtime-'));
|
|
48
|
+
run = path.join(directory, 'runtime');
|
|
49
|
+
fs.mkdirSync(run);
|
|
50
|
+
spawn.mockReturnValue({ status: 0, stdout: '', stderr: '' });
|
|
51
|
+
fs.writeFileSync(path.join(run, 'report.json'), JSON.stringify({ passed: true, checks: { godotLayout: true, windowTransitions: true } }));
|
|
52
|
+
fs.writeFileSync(path.join(run, 'native-debug-policy.json'), '\uFEFF' + JSON.stringify({ policyValuesRemoved: true }));
|
|
53
|
+
});
|
|
54
|
+
afterEach(() => { jest.resetAllMocks(); fs.rmSync(directory, { recursive: true, force: true }); });
|
|
55
|
+
test('accepts completed runtime evidence only after temporary policies are removed', () => {
|
|
56
|
+
expect(verifyInstalledRuntime(directory, run).passed).toBe(true);
|
|
57
|
+
expect(spawn.mock.calls[0][0]).toBe('powershell.exe');
|
|
58
|
+
expect(spawn.mock.calls[0][1]).toContain(path.resolve(__dirname, '../scripts/verify-elevated-desktop-runtime.ps1'));
|
|
59
|
+
});
|
|
60
|
+
test('rejects a successful runtime when machine policy cleanup did not complete', () => {
|
|
61
|
+
fs.writeFileSync(path.join(run, 'native-debug-policy.json'), JSON.stringify({ policyValuesRemoved: false }));
|
|
62
|
+
expect(() => verifyInstalledRuntime(directory, run)).toThrow(/policies must be removed/);
|
|
63
|
+
});
|
|
64
|
+
test('does not accept an empty successful process or lose its setup failure', () => {
|
|
65
|
+
fs.unlinkSync(path.join(run, 'report.json'));
|
|
66
|
+
spawn.mockReturnValue({ status: 1, stdout: '', stderr: 'Existing app policy cannot be overwritten' });
|
|
67
|
+
expect(() => verifyInstalledRuntime(directory, run)).toThrow(/Existing app policy cannot be overwritten/);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -80,6 +80,19 @@ class WorkspaceRegistry {
|
|
|
80
80
|
}
|
|
81
81
|
return this.bindings.get(bindingId) || null;
|
|
82
82
|
}
|
|
83
|
+
/** Mirrors a committed document move for workspace-scoped path filters. */
|
|
84
|
+
updateDocumentSourcePath(documentId, sourcePath, updatedAt) {
|
|
85
|
+
const binding = this.resolveBindingByDocumentId(documentId);
|
|
86
|
+
if (!binding) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
this.bindings.set(binding.bindingId, {
|
|
90
|
+
...binding,
|
|
91
|
+
sourcePath,
|
|
92
|
+
updatedAt,
|
|
93
|
+
});
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
83
96
|
getWorkspaceById(workspaceId) {
|
|
84
97
|
return this.workspaces.get(String(workspaceId || '').trim().toLowerCase()) || null;
|
|
85
98
|
}
|