@hardkas/artifacts 0.8.3-alpha → 0.8.4-alpha
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/dist/index.d.ts +14 -2
- package/dist/index.js +321 -52
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -843,6 +843,7 @@ declare const TxPlanSchema: z.ZodObject<{
|
|
|
843
843
|
rpcUrl: z.ZodOptional<z.ZodString>;
|
|
844
844
|
networkProfileRef: z.ZodOptional<z.ZodString>;
|
|
845
845
|
policyRef: z.ZodOptional<z.ZodString>;
|
|
846
|
+
policyRefs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
846
847
|
assumptionRef: z.ZodOptional<z.ZodString>;
|
|
847
848
|
}, "strip", z.ZodTypeAny, {
|
|
848
849
|
version: "1.0.0-alpha";
|
|
@@ -905,6 +906,7 @@ declare const TxPlanSchema: z.ZodObject<{
|
|
|
905
906
|
rpcUrl?: string | undefined;
|
|
906
907
|
networkProfileRef?: string | undefined;
|
|
907
908
|
policyRef?: string | undefined;
|
|
909
|
+
policyRefs?: string[] | undefined;
|
|
908
910
|
assumptionRef?: string | undefined;
|
|
909
911
|
}, {
|
|
910
912
|
version: "1.0.0-alpha";
|
|
@@ -967,6 +969,7 @@ declare const TxPlanSchema: z.ZodObject<{
|
|
|
967
969
|
rpcUrl?: string | undefined;
|
|
968
970
|
networkProfileRef?: string | undefined;
|
|
969
971
|
policyRef?: string | undefined;
|
|
972
|
+
policyRefs?: string[] | undefined;
|
|
970
973
|
assumptionRef?: string | undefined;
|
|
971
974
|
}>;
|
|
972
975
|
declare const DagContextSchema: z.ZodObject<{
|
|
@@ -2670,6 +2673,7 @@ interface TxPlanArtifact extends BaseArtifact<"txPlan"> {
|
|
|
2670
2673
|
} | undefined;
|
|
2671
2674
|
networkProfileRef?: string | undefined;
|
|
2672
2675
|
policyRef?: string | undefined;
|
|
2676
|
+
policyRefs?: string[] | undefined;
|
|
2673
2677
|
assumptionRef?: string | undefined;
|
|
2674
2678
|
}
|
|
2675
2679
|
interface SignedTxArtifact extends BaseArtifact<"signedTx"> {
|
|
@@ -2894,6 +2898,9 @@ interface VerificationContext {
|
|
|
2894
2898
|
strict?: boolean;
|
|
2895
2899
|
networkId?: NetworkId;
|
|
2896
2900
|
parent?: unknown;
|
|
2901
|
+
artifactsDir?: string;
|
|
2902
|
+
enforceMetadata?: boolean;
|
|
2903
|
+
resolveArtifact?: (id: string) => any;
|
|
2897
2904
|
}
|
|
2898
2905
|
type VerificationSeverity = CorruptionSeverity | "info" | "critical";
|
|
2899
2906
|
type VerificationIssue = {
|
|
@@ -2918,7 +2925,12 @@ type ArtifactVerificationResult = {
|
|
|
2918
2925
|
*/
|
|
2919
2926
|
declare function sortUtxosByOutpoint<T>(utxos: T[]): T[];
|
|
2920
2927
|
/**
|
|
2921
|
-
* Verifies an artifact's integrity.
|
|
2928
|
+
* Verifies an artifact's integrity synchronously.
|
|
2929
|
+
* Can take a raw object or a file path.
|
|
2930
|
+
*/
|
|
2931
|
+
declare function verifyArtifactIntegritySync(artifactOrPath: unknown): ArtifactVerificationResult;
|
|
2932
|
+
/**
|
|
2933
|
+
* Verifies an artifact's integrity asynchronously.
|
|
2922
2934
|
* Can take a raw object or a file path.
|
|
2923
2935
|
*/
|
|
2924
2936
|
declare function verifyArtifactIntegrity(artifactOrPath: unknown): Promise<ArtifactVerificationResult>;
|
|
@@ -3413,4 +3425,4 @@ declare function listDeployments(rootDir: string, networkId?: string): Promise<D
|
|
|
3413
3425
|
declare function updateDeployment(rootDir: string, networkId: string, label: string, update: Partial<DeploymentRecord>): Promise<DeploymentRecord>;
|
|
3414
3426
|
declare function deleteDeployment(rootDir: string, networkId: string, label: string): Promise<boolean>;
|
|
3415
3427
|
|
|
3416
|
-
export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactPayload, type ArtifactValidationResult, type ArtifactVerificationResult, type Assumption, type AssumptionArtifact, type AssumptionLevel, AssumptionSchema, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type DraftArtifact, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, type MigrationReceipt, type MigrationReceiptArtifact, MigrationReceiptSchema, MigrationRequiredError, type MigrationResult, type MigrationStep, NetworkInvariant, type NetworkProfile, type NetworkProfileArtifact, NetworkProfileSchema, type Policy, type PolicyArtifact, PolicySchema, ReplayInvariant, type RuntimeSession, RuntimeSessionSchema, SEMANTIC_EXCLUSIONS, STRICT_PATH_KEYS, SchemaInvariant, type ScriptCapability, ScriptCapabilitySchema, ScriptMetadataSchema, SignatureEntrySchema, SignatureMetadataEntrySchema, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, type Workflow, type WorkflowArtifact, WorkflowSchema, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canMigrate, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, detectArtifactVersion, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, generateMigrationReceipt, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, getMigrationPath, getRegisteredMigrationSteps, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateArtifactPayload, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, registerMigrationStep, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
|
|
3428
|
+
export { ARTIFACT_SCHEMAS, ARTIFACT_VERSION, AccountRefSchema, type ArtifactDiff, type ArtifactExplanation, ArtifactLineageSchema, type ArtifactLookup, type ArtifactPayload, type ArtifactValidationResult, type ArtifactVerificationResult, type Assumption, type AssumptionArtifact, type AssumptionLevel, AssumptionSchema, type BaseArtifact, BaseArtifactSchema, BasicCorrelationInvariant, BasicLineageInvariant, CURRENT_HASH_VERSION, type Clock, type CreateTxPlanArtifactOptions, type DagContext, DagContextSchema, type DeploymentIndex, type DeploymentRecord, type DeploymentSummary, type DiffEntry, type DraftArtifact, type FeeAuditResult, HARDKAS_VERSION, type HardkasArtifactBase, type HardkasArtifactMode, type HardkasArtifactSchema, HashInvariant, type IgraSignedTxArtifact, type IgraTxPlanArtifact, type IgraTxReceiptArtifact, type IgraTxRequestArtifact, type Invariant, type InvariantContext, type InvariantViolation, InvariantWatcher, LifecycleInvariant, type LineageOptions, type LineageValidationResult, LocalnetUtxoSchemaV2, type MigrationReceipt, type MigrationReceiptArtifact, MigrationReceiptSchema, MigrationRequiredError, type MigrationResult, type MigrationStep, NetworkInvariant, type NetworkProfile, type NetworkProfileArtifact, NetworkProfileSchema, type Policy, type PolicyArtifact, PolicySchema, ReplayInvariant, type RuntimeSession, RuntimeSessionSchema, SEMANTIC_EXCLUSIONS, STRICT_PATH_KEYS, SchemaInvariant, type ScriptCapability, ScriptCapabilitySchema, ScriptMetadataSchema, SignatureEntrySchema, SignatureMetadataEntrySchema, type SignedTx, type SignedTxArtifact, type SignedTxArtifactV1, SignedTxSchema, type Snapshot, type SnapshotArtifact, SnapshotSchema, type TxOutputArtifact, type TxPlan, type TxPlanArtifact, type TxPlanArtifactV1, TxPlanSchema, type TxReceipt, type TxReceiptArtifact, type TxReceiptArtifactV1, TxReceiptSchema, type TxTrace, type TxTraceArtifact, type TxTraceArtifactV1, TxTraceSchema, type UtxoArtifact, type VerificationContext, type VerificationIssue, type VerificationSeverity, type WatcherOptions, type Workflow, type WorkflowArtifact, WorkflowSchema, assertDecimalBigIntString, assertEvmAddress, assertEvmTxHash, assertHexData, assertValidIgraSignedTxArtifact, assertValidIgraTxPlanArtifact, assertValidIgraTxReceiptArtifact, assertValidSignedTxArtifact, assertValidTxPlanArtifact, assertValidTxReceiptArtifact, bigIntReplacer, calculateContentHash, canMigrate, canonicalStringify, createDeploymentRecord, createIgraDeployPlanId, createIgraPlanId, createIgraSignedId, createSimulatedSignedTxArtifact, createSimulatedTxReceipt, createTxPlanArtifact, defaultClock, deleteDeployment, detectArtifactVersion, diffArtifacts, explainArtifact, formatSignedTxArtifact, formatTxPlanArtifact, formatTxReceiptArtifact, generateMigrationReceipt, getBroadcastableSignedTransaction, getDefaultL2ReceiptsDir, getDefaultReceiptPath, getL2ReceiptPath, getMigrationPath, getRegisteredMigrationSteps, isIgraTxPlanArtifact, listDeployments, listIgraTxReceiptArtifacts, loadDeployment, loadIgraTxReceiptArtifact, migrateArtifactPayload, migrateToCanonical, readArtifact, readSignedTxArtifact, readTxPlanArtifact, readTxReceiptArtifact, recomputeMass, registerMigrationStep, saveDeployment, saveIgraTxReceiptArtifact, sortUtxosByOutpoint, txOutputFromArtifact, txOutputToArtifact, updateDeployment, updateDeploymentStatus, utxoFromArtifact, utxoToArtifact, validateArtifact, validateIgraSignedTxArtifact, validateIgraTxPlanArtifact, validateIgraTxReceiptArtifact, validateSignedTxArtifact, validateTxPlanArtifact, validateTxReceiptArtifact, verifyArtifact, verifyArtifactFile, verifyArtifactIntegrity, verifyArtifactIntegritySync, verifyArtifactReplay, verifyArtifactSemantics, verifyFeeSemantics, verifyLineage, writeArtifact };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@hardkas/artifacts",
|
|
4
|
-
version: "0.8.
|
|
4
|
+
version: "0.8.4-alpha",
|
|
5
5
|
type: "module",
|
|
6
6
|
license: "MIT",
|
|
7
7
|
author: "Javier Rodriguez",
|
|
@@ -416,6 +416,7 @@ var TxPlanSchema = BaseArtifactSchema.extend({
|
|
|
416
416
|
rpcUrl: z.string().optional(),
|
|
417
417
|
networkProfileRef: z.string().optional(),
|
|
418
418
|
policyRef: z.string().optional(),
|
|
419
|
+
policyRefs: z.array(z.string()).optional(),
|
|
419
420
|
assumptionRef: z.string().optional()
|
|
420
421
|
});
|
|
421
422
|
var DagContextSchema = z.object({
|
|
@@ -581,6 +582,7 @@ var RuntimeSessionSchema = BaseArtifactSchema.extend({
|
|
|
581
582
|
|
|
582
583
|
// src/verify.ts
|
|
583
584
|
import fs from "fs";
|
|
585
|
+
import path from "path";
|
|
584
586
|
|
|
585
587
|
// src/feeVerify.ts
|
|
586
588
|
import {
|
|
@@ -815,15 +817,15 @@ function sortUtxosByOutpoint(utxos) {
|
|
|
815
817
|
return deterministicCompare2(aId, bId);
|
|
816
818
|
});
|
|
817
819
|
}
|
|
818
|
-
|
|
820
|
+
function verifyArtifactIntegritySync(artifactOrPath) {
|
|
819
821
|
const result = {
|
|
820
822
|
ok: false,
|
|
821
823
|
errors: [],
|
|
822
824
|
issues: []
|
|
823
825
|
};
|
|
824
|
-
const addError = (code, message,
|
|
826
|
+
const addError = (code, message, path5) => {
|
|
825
827
|
result.errors.push(message);
|
|
826
|
-
result.issues.push({ code, severity: "error", message, path:
|
|
828
|
+
result.issues.push({ code, severity: "error", message, path: path5 });
|
|
827
829
|
};
|
|
828
830
|
let artifact;
|
|
829
831
|
try {
|
|
@@ -937,6 +939,37 @@ async function verifyArtifactIntegrity(artifactOrPath) {
|
|
|
937
939
|
return result;
|
|
938
940
|
}
|
|
939
941
|
}
|
|
942
|
+
async function verifyArtifactIntegrity(artifactOrPath) {
|
|
943
|
+
return verifyArtifactIntegritySync(artifactOrPath);
|
|
944
|
+
}
|
|
945
|
+
function findFileByHash(hash, dirs) {
|
|
946
|
+
const shortHash = hash.startsWith("plan-") || hash.startsWith("signed-") ? hash : hash.slice(0, 16);
|
|
947
|
+
for (const dir of dirs) {
|
|
948
|
+
if (!fs.existsSync(dir)) continue;
|
|
949
|
+
try {
|
|
950
|
+
const files = fs.readdirSync(dir);
|
|
951
|
+
if (files.includes(`${hash}.json`)) {
|
|
952
|
+
return path.join(dir, `${hash}.json`);
|
|
953
|
+
}
|
|
954
|
+
for (const file of files) {
|
|
955
|
+
if (!file.endsWith(".json")) continue;
|
|
956
|
+
if (file.includes(hash) || file.includes(shortHash) || file.includes(hash.slice(0, 8))) {
|
|
957
|
+
const filePath = path.join(dir, file);
|
|
958
|
+
try {
|
|
959
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
960
|
+
const obj = JSON.parse(content);
|
|
961
|
+
if (obj.contentHash === hash || obj.artifactId === hash || obj.planId === hash || obj.signedId === hash || obj.txId === hash) {
|
|
962
|
+
return filePath;
|
|
963
|
+
}
|
|
964
|
+
} catch {
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
} catch {
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
940
973
|
function verifyArtifactSemantics(artifact, context = {}) {
|
|
941
974
|
const result = {
|
|
942
975
|
ok: true,
|
|
@@ -962,6 +995,225 @@ function verifyArtifactSemantics(artifact, context = {}) {
|
|
|
962
995
|
});
|
|
963
996
|
}
|
|
964
997
|
const v = artifact;
|
|
998
|
+
let parentObj = null;
|
|
999
|
+
if (strict) {
|
|
1000
|
+
const searchDirs = [];
|
|
1001
|
+
if (context.artifactsDir) {
|
|
1002
|
+
searchDirs.push(context.artifactsDir);
|
|
1003
|
+
}
|
|
1004
|
+
searchDirs.push(path.join(process.cwd(), ".hardkas", "artifacts"));
|
|
1005
|
+
searchDirs.push(path.join(process.cwd(), "artifacts"));
|
|
1006
|
+
const policyRefs = [];
|
|
1007
|
+
if (Array.isArray(v.policyRefs)) {
|
|
1008
|
+
policyRefs.push(...v.policyRefs);
|
|
1009
|
+
} else if (typeof v.policyRef === "string") {
|
|
1010
|
+
policyRefs.push(v.policyRef);
|
|
1011
|
+
}
|
|
1012
|
+
for (const ref of policyRefs) {
|
|
1013
|
+
let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
|
|
1014
|
+
if (!refObj) {
|
|
1015
|
+
const refFile = findFileByHash(ref, searchDirs);
|
|
1016
|
+
if (refFile) {
|
|
1017
|
+
try {
|
|
1018
|
+
const content = fs.readFileSync(refFile, "utf-8");
|
|
1019
|
+
refObj = JSON.parse(content);
|
|
1020
|
+
} catch (e) {
|
|
1021
|
+
addIssue({
|
|
1022
|
+
code: "REFERENCE_CORRUPT",
|
|
1023
|
+
severity: "error",
|
|
1024
|
+
message: `Failed to read policy ${ref}: ${e.message}`
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (!refObj) {
|
|
1030
|
+
addIssue({
|
|
1031
|
+
code: "REFERENCE_MISSING",
|
|
1032
|
+
severity: "error",
|
|
1033
|
+
message: `Referenced policy artifact ${ref} not found in workspace`
|
|
1034
|
+
});
|
|
1035
|
+
} else {
|
|
1036
|
+
try {
|
|
1037
|
+
const integrity = verifyArtifactIntegritySync(refObj);
|
|
1038
|
+
if (!integrity.ok) {
|
|
1039
|
+
addIssue({
|
|
1040
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1041
|
+
severity: "error",
|
|
1042
|
+
message: `Referenced policy ${ref} integrity check failed: ${integrity.errors.join(", ")}`
|
|
1043
|
+
});
|
|
1044
|
+
} else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
|
|
1045
|
+
addIssue({
|
|
1046
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1047
|
+
severity: "error",
|
|
1048
|
+
message: `Policy reference mismatch: expected ${ref}, got ${refObj.contentHash}`
|
|
1049
|
+
});
|
|
1050
|
+
} else {
|
|
1051
|
+
if (refObj.schema === "hardkas.policy.v1") {
|
|
1052
|
+
if (refObj.decision === "DENY") {
|
|
1053
|
+
addIssue({
|
|
1054
|
+
code: "POLICY_VIOLATION",
|
|
1055
|
+
severity: "error",
|
|
1056
|
+
message: `Policy evaluation rejected: decision is DENY`
|
|
1057
|
+
});
|
|
1058
|
+
} else if (refObj.decision !== "ALLOW") {
|
|
1059
|
+
addIssue({
|
|
1060
|
+
code: "POLICY_VIOLATION",
|
|
1061
|
+
severity: "error",
|
|
1062
|
+
message: `Policy evaluation rejected: decision is invalid (${refObj.decision})`
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
const failedRules = refObj.rules?.filter((r) => r.result === "FAIL") || [];
|
|
1066
|
+
if (failedRules.length > 0) {
|
|
1067
|
+
addIssue({
|
|
1068
|
+
code: "POLICY_VIOLATION",
|
|
1069
|
+
severity: "error",
|
|
1070
|
+
message: `Policy rules failed: ${failedRules.map((r) => r.id).join(", ")}`
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
} catch (e) {
|
|
1076
|
+
addIssue({
|
|
1077
|
+
code: "REFERENCE_CORRUPT",
|
|
1078
|
+
severity: "error",
|
|
1079
|
+
message: `Failed to read/verify policy ${ref}: ${e.message}`
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
if (typeof v.networkProfileRef === "string") {
|
|
1085
|
+
const ref = v.networkProfileRef;
|
|
1086
|
+
let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
|
|
1087
|
+
if (!refObj) {
|
|
1088
|
+
const refFile = findFileByHash(ref, searchDirs);
|
|
1089
|
+
if (refFile) {
|
|
1090
|
+
try {
|
|
1091
|
+
refObj = JSON.parse(fs.readFileSync(refFile, "utf-8"));
|
|
1092
|
+
} catch {
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (!refObj) {
|
|
1097
|
+
addIssue({
|
|
1098
|
+
code: "REFERENCE_MISSING",
|
|
1099
|
+
severity: "error",
|
|
1100
|
+
message: `Referenced network profile ${ref} not found in workspace`
|
|
1101
|
+
});
|
|
1102
|
+
} else {
|
|
1103
|
+
try {
|
|
1104
|
+
const integrity = verifyArtifactIntegritySync(refObj);
|
|
1105
|
+
if (!integrity.ok) {
|
|
1106
|
+
addIssue({
|
|
1107
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1108
|
+
severity: "error",
|
|
1109
|
+
message: `Referenced profile ${ref} integrity check failed`
|
|
1110
|
+
});
|
|
1111
|
+
} else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
|
|
1112
|
+
addIssue({
|
|
1113
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1114
|
+
severity: "error",
|
|
1115
|
+
message: `Profile reference mismatch: expected ${ref}, got ${refObj.contentHash}`
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
} catch (e) {
|
|
1119
|
+
addIssue({
|
|
1120
|
+
code: "REFERENCE_CORRUPT",
|
|
1121
|
+
severity: "error",
|
|
1122
|
+
message: `Failed to verify profile ${ref}`
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
if (typeof v.assumptionRef === "string") {
|
|
1128
|
+
const ref = v.assumptionRef;
|
|
1129
|
+
let refObj = context.resolveArtifact ? context.resolveArtifact(ref) : null;
|
|
1130
|
+
if (!refObj) {
|
|
1131
|
+
const refFile = findFileByHash(ref, searchDirs);
|
|
1132
|
+
if (refFile) {
|
|
1133
|
+
try {
|
|
1134
|
+
refObj = JSON.parse(fs.readFileSync(refFile, "utf-8"));
|
|
1135
|
+
} catch {
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
if (!refObj) {
|
|
1140
|
+
addIssue({
|
|
1141
|
+
code: "REFERENCE_MISSING",
|
|
1142
|
+
severity: "error",
|
|
1143
|
+
message: `Referenced assumption ${ref} not found in workspace`
|
|
1144
|
+
});
|
|
1145
|
+
} else {
|
|
1146
|
+
try {
|
|
1147
|
+
const integrity = verifyArtifactIntegritySync(refObj);
|
|
1148
|
+
if (!integrity.ok) {
|
|
1149
|
+
addIssue({
|
|
1150
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1151
|
+
severity: "error",
|
|
1152
|
+
message: `Referenced assumption ${ref} integrity check failed`
|
|
1153
|
+
});
|
|
1154
|
+
} else if (refObj.contentHash !== ref && refObj.artifactId !== ref) {
|
|
1155
|
+
addIssue({
|
|
1156
|
+
code: "REFERENCE_HASH_MISMATCH",
|
|
1157
|
+
severity: "error",
|
|
1158
|
+
message: `Assumption reference mismatch: expected ${ref}, got ${refObj.contentHash}`
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
addIssue({
|
|
1163
|
+
code: "REFERENCE_CORRUPT",
|
|
1164
|
+
severity: "error",
|
|
1165
|
+
message: `Failed to verify assumption ${ref}`
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
let parentId;
|
|
1171
|
+
const lineage = v.lineage;
|
|
1172
|
+
if (lineage?.parentArtifactId && lineage?.parentArtifactId !== lineage?.artifactId) {
|
|
1173
|
+
parentId = lineage?.parentArtifactId;
|
|
1174
|
+
} else if (v.schema === "hardkas.signedTx") {
|
|
1175
|
+
parentId = v.sourcePlanId;
|
|
1176
|
+
} else if (v.schema === "hardkas.txReceipt") {
|
|
1177
|
+
parentId = v.sourceSignedId || lineage?.parentArtifactId;
|
|
1178
|
+
}
|
|
1179
|
+
if (parentId) {
|
|
1180
|
+
parentObj = context.resolveArtifact ? context.resolveArtifact(parentId) : null;
|
|
1181
|
+
if (!parentObj) {
|
|
1182
|
+
const parentFile = findFileByHash(parentId, searchDirs);
|
|
1183
|
+
if (parentFile) {
|
|
1184
|
+
try {
|
|
1185
|
+
parentObj = JSON.parse(fs.readFileSync(parentFile, "utf-8"));
|
|
1186
|
+
} catch (e) {
|
|
1187
|
+
addIssue({
|
|
1188
|
+
code: "PARENT_CORRUPT",
|
|
1189
|
+
severity: "error",
|
|
1190
|
+
message: `Failed to read parent ${parentId}: ${e.message}`
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (!parentObj) {
|
|
1196
|
+
addIssue({
|
|
1197
|
+
code: "PARENT_MISSING",
|
|
1198
|
+
severity: "warning",
|
|
1199
|
+
message: `Parent artifact ${parentId} not found in workspace`
|
|
1200
|
+
});
|
|
1201
|
+
} else {
|
|
1202
|
+
try {
|
|
1203
|
+
const parentSem = verifyArtifactSemantics(parentObj, { ...context, strict: true });
|
|
1204
|
+
if (!parentSem.ok) {
|
|
1205
|
+
parentSem.issues.forEach((issue) => addIssue(issue));
|
|
1206
|
+
}
|
|
1207
|
+
} catch (e) {
|
|
1208
|
+
addIssue({
|
|
1209
|
+
code: "PARENT_CORRUPT",
|
|
1210
|
+
severity: "error",
|
|
1211
|
+
message: `Failed to verify parent ${parentId}: ${e.message}`
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
965
1217
|
if (v.createdAt && typeof v.createdAt === "string") {
|
|
966
1218
|
const created = new Date(v.createdAt).getTime();
|
|
967
1219
|
const now = clock.now();
|
|
@@ -980,31 +1232,47 @@ function verifyArtifactSemantics(artifact, context = {}) {
|
|
|
980
1232
|
});
|
|
981
1233
|
}
|
|
982
1234
|
}
|
|
983
|
-
const lineageAudit = verifyLineage(v, context.parent, { strict });
|
|
1235
|
+
const lineageAudit = verifyLineage(v, parentObj || context.parent, { strict });
|
|
984
1236
|
if (!lineageAudit.ok || strict && !v.lineage && v.schema !== "hardkas.workflow.v1") {
|
|
985
1237
|
lineageAudit.issues.forEach((issue) => {
|
|
986
1238
|
addIssue(issue);
|
|
987
1239
|
});
|
|
988
1240
|
}
|
|
989
1241
|
if (strict) {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1242
|
+
const enforceMetadata = context.enforceMetadata ?? true;
|
|
1243
|
+
if (enforceMetadata) {
|
|
1244
|
+
if (!v.workflowId)
|
|
1245
|
+
addIssue({
|
|
1246
|
+
code: "MISSING_WORKFLOW_ID",
|
|
1247
|
+
severity: "error",
|
|
1248
|
+
message: "Strict mode requires workflowId"
|
|
1249
|
+
});
|
|
1250
|
+
if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1")
|
|
1251
|
+
addIssue({
|
|
1252
|
+
code: "MISSING_ASSUMPTION_LEVEL",
|
|
1253
|
+
severity: "error",
|
|
1254
|
+
message: "Strict mode requires assumptionLevel"
|
|
1255
|
+
});
|
|
1256
|
+
if (!v.executionMode && !v.mode)
|
|
1257
|
+
addIssue({
|
|
1258
|
+
code: "MISSING_EXECUTION_MODE",
|
|
1259
|
+
severity: "error",
|
|
1260
|
+
message: "Strict mode requires executionMode"
|
|
1261
|
+
});
|
|
1262
|
+
} else {
|
|
1263
|
+
if (!v.workflowId)
|
|
1264
|
+
addIssue({
|
|
1265
|
+
code: "MISSING_WORKFLOW_ID",
|
|
1266
|
+
severity: "warning",
|
|
1267
|
+
message: "Missing workflowId"
|
|
1268
|
+
});
|
|
1269
|
+
if (!v.assumptionLevel && v.schema !== "hardkas.workflow.v1")
|
|
1270
|
+
addIssue({
|
|
1271
|
+
code: "MISSING_ASSUMPTION_LEVEL",
|
|
1272
|
+
severity: "warning",
|
|
1273
|
+
message: "Missing assumptionLevel"
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1008
1276
|
} else {
|
|
1009
1277
|
if (!v.workflowId)
|
|
1010
1278
|
addIssue({
|
|
@@ -1375,8 +1643,8 @@ function canMigrate(artifact, targetVersion = ARTIFACT_VERSION) {
|
|
|
1375
1643
|
if (currentVersion === targetVersion) {
|
|
1376
1644
|
return true;
|
|
1377
1645
|
}
|
|
1378
|
-
const
|
|
1379
|
-
return
|
|
1646
|
+
const path5 = getMigrationPath(currentVersion, targetVersion);
|
|
1647
|
+
return path5.length > 0;
|
|
1380
1648
|
}
|
|
1381
1649
|
function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, options) {
|
|
1382
1650
|
const currentVersion = detectArtifactVersion(artifact);
|
|
@@ -1391,8 +1659,8 @@ function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, opti
|
|
|
1391
1659
|
if (options?.strictPolicy) {
|
|
1392
1660
|
throw new MigrationRequiredError(currentVersion, targetVersion);
|
|
1393
1661
|
}
|
|
1394
|
-
const
|
|
1395
|
-
if (
|
|
1662
|
+
const path5 = getMigrationPath(currentVersion, targetVersion);
|
|
1663
|
+
if (path5.length === 0) {
|
|
1396
1664
|
throw new Error(
|
|
1397
1665
|
`No migration path from version "${currentVersion}" to "${targetVersion}". Registered steps: [${migrationRegistry.map((s) => `${s.fromVersion}\u2192${s.toVersion}`).join(", ")}]`
|
|
1398
1666
|
);
|
|
@@ -1401,7 +1669,7 @@ function migrateArtifactPayload(artifact, targetVersion = ARTIFACT_VERSION, opti
|
|
|
1401
1669
|
const originalLineage = artifact.lineage;
|
|
1402
1670
|
let current = { ...artifact };
|
|
1403
1671
|
const appliedSteps = [];
|
|
1404
|
-
for (const step of
|
|
1672
|
+
for (const step of path5) {
|
|
1405
1673
|
current = step.transform(current);
|
|
1406
1674
|
appliedSteps.push({
|
|
1407
1675
|
fromVersion: step.fromVersion,
|
|
@@ -1478,7 +1746,7 @@ function generateMigrationReceipt(oldArtifact, newArtifact, migrationId) {
|
|
|
1478
1746
|
|
|
1479
1747
|
// src/io.ts
|
|
1480
1748
|
import fs2 from "fs/promises";
|
|
1481
|
-
import
|
|
1749
|
+
import path2 from "path";
|
|
1482
1750
|
import { writeFileAtomic } from "@hardkas/core";
|
|
1483
1751
|
var bigIntReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
|
|
1484
1752
|
async function writeArtifact(filePath, artifact) {
|
|
@@ -1489,10 +1757,10 @@ async function writeArtifact(filePath, artifact) {
|
|
|
1489
1757
|
const artifactObj = typeof artifact === "string" ? JSON.parse(artifact) : artifact;
|
|
1490
1758
|
const id = artifactObj.planId || artifactObj.signedId || artifactObj.txId || Date.now().toString(36);
|
|
1491
1759
|
const prefix = artifactObj.schema ? artifactObj.schema.split(".")[1] || "artifact" : "artifact";
|
|
1492
|
-
targetPath =
|
|
1760
|
+
targetPath = path2.join(filePath, `${prefix}-${id}.json`);
|
|
1493
1761
|
console.log(
|
|
1494
1762
|
`
|
|
1495
|
-
Note: Provided path is a directory. Auto-generating artifact filename: ${
|
|
1763
|
+
Note: Provided path is a directory. Auto-generating artifact filename: ${path2.basename(targetPath)}`
|
|
1496
1764
|
);
|
|
1497
1765
|
}
|
|
1498
1766
|
} catch (e) {
|
|
@@ -1500,14 +1768,14 @@ Note: Provided path is a directory. Auto-generating artifact filename: ${path.ba
|
|
|
1500
1768
|
const artifactObj = typeof artifact === "string" ? JSON.parse(artifact) : artifact;
|
|
1501
1769
|
const id = artifactObj.planId || artifactObj.signedId || artifactObj.txId || Date.now().toString(36);
|
|
1502
1770
|
const prefix = artifactObj.schema ? artifactObj.schema.split(".")[1] || "artifact" : "artifact";
|
|
1503
|
-
targetPath =
|
|
1771
|
+
targetPath = path2.join(filePath, `${prefix}-${id}.json`);
|
|
1504
1772
|
}
|
|
1505
1773
|
}
|
|
1506
1774
|
const content = typeof artifact === "string" ? artifact : JSON.stringify(artifact, bigIntReplacer, 2) + "\n";
|
|
1507
1775
|
await writeFileAtomic(targetPath, content);
|
|
1508
1776
|
}
|
|
1509
1777
|
function getDefaultReceiptPath(txId, cwd = process.cwd()) {
|
|
1510
|
-
return
|
|
1778
|
+
return path2.join(cwd, "artifacts", "receipts", `${txId}.json`);
|
|
1511
1779
|
}
|
|
1512
1780
|
async function readArtifact(filePath) {
|
|
1513
1781
|
try {
|
|
@@ -2040,15 +2308,15 @@ async function explainArtifact(artifactUnknown) {
|
|
|
2040
2308
|
|
|
2041
2309
|
// src/igra-io.ts
|
|
2042
2310
|
import fs3 from "fs/promises";
|
|
2043
|
-
import
|
|
2311
|
+
import path3 from "path";
|
|
2044
2312
|
import { deterministicCompare as deterministicCompare3 } from "@hardkas/core";
|
|
2045
2313
|
function getDefaultL2ReceiptsDir(cwd = process.cwd()) {
|
|
2046
|
-
return
|
|
2314
|
+
return path3.join(cwd, ".hardkas", "l2-receipts");
|
|
2047
2315
|
}
|
|
2048
2316
|
function getL2ReceiptPath(txHash, options) {
|
|
2049
2317
|
validateTxHash(txHash);
|
|
2050
2318
|
const dir = getDefaultL2ReceiptsDir(options?.cwd);
|
|
2051
|
-
return
|
|
2319
|
+
return path3.join(dir, `${txHash}.igra.receipt.json`);
|
|
2052
2320
|
}
|
|
2053
2321
|
async function saveIgraTxReceiptArtifact(receipt, options) {
|
|
2054
2322
|
assertValidIgraTxReceiptArtifact(receipt);
|
|
@@ -2070,7 +2338,7 @@ async function listIgraTxReceiptArtifacts(options) {
|
|
|
2070
2338
|
const receipts = [];
|
|
2071
2339
|
for (const file of receiptFiles) {
|
|
2072
2340
|
try {
|
|
2073
|
-
const data = await readArtifact(
|
|
2341
|
+
const data = await readArtifact(path3.join(dir, file));
|
|
2074
2342
|
if (data && typeof data === "object" && data.schema === "hardkas.igraTxReceipt.v1") {
|
|
2075
2343
|
receipts.push(data);
|
|
2076
2344
|
}
|
|
@@ -2103,26 +2371,26 @@ function diffArtifacts(left, right) {
|
|
|
2103
2371
|
entries
|
|
2104
2372
|
};
|
|
2105
2373
|
}
|
|
2106
|
-
function compareRecursive(left, right,
|
|
2374
|
+
function compareRecursive(left, right, path5, entries) {
|
|
2107
2375
|
if (isPrimitive(left) || isPrimitive(right)) {
|
|
2108
2376
|
if (left !== right) {
|
|
2109
|
-
entries.push({ path:
|
|
2377
|
+
entries.push({ path: path5, kind: "changed", left, right });
|
|
2110
2378
|
}
|
|
2111
2379
|
return;
|
|
2112
2380
|
}
|
|
2113
2381
|
if (Array.isArray(left) || Array.isArray(right)) {
|
|
2114
2382
|
if (!Array.isArray(left) || !Array.isArray(right)) {
|
|
2115
|
-
entries.push({ path:
|
|
2383
|
+
entries.push({ path: path5, kind: "changed", left, right });
|
|
2116
2384
|
return;
|
|
2117
2385
|
}
|
|
2118
2386
|
const maxLength = Math.max(left.length, right.length);
|
|
2119
2387
|
for (let i = 0; i < maxLength; i++) {
|
|
2120
2388
|
if (i >= left.length) {
|
|
2121
|
-
entries.push({ path: `${
|
|
2389
|
+
entries.push({ path: `${path5}[${i}]`, kind: "added", right: right[i] });
|
|
2122
2390
|
} else if (i >= right.length) {
|
|
2123
|
-
entries.push({ path: `${
|
|
2391
|
+
entries.push({ path: `${path5}[${i}]`, kind: "removed", left: left[i] });
|
|
2124
2392
|
} else {
|
|
2125
|
-
compareRecursive(left[i], right[i], `${
|
|
2393
|
+
compareRecursive(left[i], right[i], `${path5}[${i}]`, entries);
|
|
2126
2394
|
}
|
|
2127
2395
|
}
|
|
2128
2396
|
return;
|
|
@@ -2131,7 +2399,7 @@ function compareRecursive(left, right, path4, entries) {
|
|
|
2131
2399
|
const rightKeys = Object.keys(right).filter((k) => !SEMANTIC_EXCLUSIONS.has(k));
|
|
2132
2400
|
const allKeys = /* @__PURE__ */ new Set([...leftKeys, ...rightKeys]);
|
|
2133
2401
|
for (const key of allKeys) {
|
|
2134
|
-
const nextPath =
|
|
2402
|
+
const nextPath = path5 === "$" ? key : `${path5}.${key}`;
|
|
2135
2403
|
if (!leftKeys.includes(key)) {
|
|
2136
2404
|
entries.push({ path: nextPath, kind: "added", right: right[key] });
|
|
2137
2405
|
} else if (!rightKeys.includes(key)) {
|
|
@@ -2195,16 +2463,16 @@ function updateDeploymentStatus(record, newStatus, txId) {
|
|
|
2195
2463
|
// src/deployment-store.ts
|
|
2196
2464
|
import fs4 from "fs/promises";
|
|
2197
2465
|
import { existsSync } from "fs";
|
|
2198
|
-
import
|
|
2466
|
+
import path4 from "path";
|
|
2199
2467
|
import { writeFileAtomic as writeFileAtomic2 } from "@hardkas/core";
|
|
2200
2468
|
async function saveDeployment(rootDir, record) {
|
|
2201
|
-
const deploymentsDir =
|
|
2202
|
-
const targetPath =
|
|
2469
|
+
const deploymentsDir = path4.join(rootDir, ".hardkas", "deployments", record.networkId);
|
|
2470
|
+
const targetPath = path4.join(deploymentsDir, `${record.label}.json`);
|
|
2203
2471
|
await writeFileAtomic2(targetPath, JSON.stringify(record, null, 2));
|
|
2204
2472
|
return targetPath;
|
|
2205
2473
|
}
|
|
2206
2474
|
async function loadDeployment(rootDir, networkId, label) {
|
|
2207
|
-
const targetPath =
|
|
2475
|
+
const targetPath = path4.join(
|
|
2208
2476
|
rootDir,
|
|
2209
2477
|
".hardkas",
|
|
2210
2478
|
"deployments",
|
|
@@ -2216,18 +2484,18 @@ async function loadDeployment(rootDir, networkId, label) {
|
|
|
2216
2484
|
return JSON.parse(content);
|
|
2217
2485
|
}
|
|
2218
2486
|
async function listDeployments(rootDir, networkId) {
|
|
2219
|
-
const baseDir =
|
|
2487
|
+
const baseDir = path4.join(rootDir, ".hardkas", "deployments");
|
|
2220
2488
|
if (!existsSync(baseDir)) return [];
|
|
2221
2489
|
const summaries = [];
|
|
2222
2490
|
const networks = networkId ? [networkId] : await fs4.readdir(baseDir);
|
|
2223
2491
|
for (const net of networks) {
|
|
2224
|
-
const netDir =
|
|
2492
|
+
const netDir = path4.join(baseDir, net);
|
|
2225
2493
|
if (!existsSync(netDir)) continue;
|
|
2226
2494
|
const files = await fs4.readdir(netDir);
|
|
2227
2495
|
for (const file of files) {
|
|
2228
2496
|
if (!file.endsWith(".json")) continue;
|
|
2229
2497
|
try {
|
|
2230
|
-
const content = await fs4.readFile(
|
|
2498
|
+
const content = await fs4.readFile(path4.join(netDir, file), "utf-8");
|
|
2231
2499
|
const record = JSON.parse(content);
|
|
2232
2500
|
const summary = {
|
|
2233
2501
|
label: record.label,
|
|
@@ -2260,7 +2528,7 @@ async function updateDeployment(rootDir, networkId, label, update) {
|
|
|
2260
2528
|
return updated;
|
|
2261
2529
|
}
|
|
2262
2530
|
async function deleteDeployment(rootDir, networkId, label) {
|
|
2263
|
-
const targetPath =
|
|
2531
|
+
const targetPath = path4.join(
|
|
2264
2532
|
rootDir,
|
|
2265
2533
|
".hardkas",
|
|
2266
2534
|
"deployments",
|
|
@@ -2375,6 +2643,7 @@ export {
|
|
|
2375
2643
|
verifyArtifact,
|
|
2376
2644
|
verifyArtifactFile,
|
|
2377
2645
|
verifyArtifactIntegrity,
|
|
2646
|
+
verifyArtifactIntegritySync,
|
|
2378
2647
|
verifyArtifactReplay,
|
|
2379
2648
|
verifyArtifactSemantics,
|
|
2380
2649
|
verifyFeeSemantics,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardkas/artifacts",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4-alpha",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Javier Rodriguez",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"zod": "^3.24.1",
|
|
27
|
-
"@hardkas/core": "0.8.
|
|
28
|
-
"@hardkas/tx-builder": "0.8.
|
|
27
|
+
"@hardkas/core": "0.8.4-alpha",
|
|
28
|
+
"@hardkas/tx-builder": "0.8.4-alpha"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"tsup": "^8.3.5",
|