@runveric/cli 0.2.0 → 0.4.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 +24 -8
- package/dist/runveric.mjs +1467 -108
- package/dist/runveric.mjs.map +1 -1
- package/package.json +3 -3
package/dist/runveric.mjs
CHANGED
|
@@ -212,16 +212,18 @@ var require_wire_identity = __commonJS({
|
|
|
212
212
|
Object.defineProperty(exports, "__esModule", {
|
|
213
213
|
value: true
|
|
214
214
|
});
|
|
215
|
-
exports.PROBLEM_TYPE_BASE = exports.CATALOG_ARTIFACT_MEDIA_TYPE = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V1 = exports.CATALOG_RELEASE_SCHEMA_V1 = exports.EVIDENCE_PACK_SCHEMA_VERSION = exports.RUNNER_PROTOCOL_VERSION = exports.PACKAGE_WORK_ITEM_VERSION = exports.ACTION_MANIFEST_API_VERSION = exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = exports.PACKAGE_RESULT_PROTOCOL_VERSION = void 0;
|
|
215
|
+
exports.PROBLEM_TYPE_BASE = exports.CATALOG_ARTIFACT_MEDIA_TYPE = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V2 = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V1 = exports.CATALOG_RELEASE_SCHEMA_V1 = exports.EVIDENCE_PACK_SCHEMA_VERSION = exports.ACTION_PROTOCOL_V1 = exports.RUNNER_PROTOCOL_VERSION = exports.PACKAGE_WORK_ITEM_VERSION = exports.ACTION_MANIFEST_API_VERSION = exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = exports.PACKAGE_RESULT_PROTOCOL_VERSION = void 0;
|
|
216
216
|
exports.problemType = problemType;
|
|
217
217
|
exports.PACKAGE_RESULT_PROTOCOL_VERSION = "runveric.dev/package-result/v1";
|
|
218
218
|
exports.PACKAGE_EXECUTION_PROTOCOL_VERSION = "runveric.dev/package-execution/v1";
|
|
219
219
|
exports.ACTION_MANIFEST_API_VERSION = "runveric.dev/action/v1";
|
|
220
220
|
exports.PACKAGE_WORK_ITEM_VERSION = "runveric.dev/package-work-item/v1";
|
|
221
221
|
exports.RUNNER_PROTOCOL_VERSION = "runveric.dev/runner-channel/v2";
|
|
222
|
+
exports.ACTION_PROTOCOL_V1 = "runveric.dev/action-protocol/v1";
|
|
222
223
|
exports.EVIDENCE_PACK_SCHEMA_VERSION = "runveric.dev/evidence-pack/v1";
|
|
223
224
|
exports.CATALOG_RELEASE_SCHEMA_V1 = "runveric.dev/catalog-release/v1";
|
|
224
225
|
exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V1 = "runveric.dev/catalog-action/v1";
|
|
226
|
+
exports.CATALOG_ACTION_ARTIFACT_SCHEMA_V2 = "runveric.dev/catalog-action/v2";
|
|
225
227
|
exports.CATALOG_ARTIFACT_MEDIA_TYPE = "application/vnd.runveric.catalog-artifact+json";
|
|
226
228
|
exports.PROBLEM_TYPE_BASE = "https://runveric.dev/errors";
|
|
227
229
|
function problemType(slug) {
|
|
@@ -611,16 +613,134 @@ var require_catalog_release = __commonJS({
|
|
|
611
613
|
Object.defineProperty(exports, "__esModule", {
|
|
612
614
|
value: true
|
|
613
615
|
});
|
|
614
|
-
exports.ARTIFACT_DIGEST_PATTERN = exports.ARTIFACT_REPOSITORY_PATTERN = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_VERSIONS = exports.CATALOG_RELEASE_SCHEMA_VERSIONS = void 0;
|
|
616
|
+
exports.CatalogReleaseStateError = exports.CATALOG_SYNC_STALE_AFTER_MINUTES = exports.CATALOG_SYNC_INTERVAL_MINUTES = exports.CATALOG_SYNC_SOURCES = exports.CATALOG_SYNC_RUN_OUTCOMES = exports.ARTIFACT_DIGEST_PATTERN = exports.ARTIFACT_REPOSITORY_PATTERN = exports.CATALOG_ACTION_ARTIFACT_SCHEMA_VERSIONS = exports.CATALOG_RELEASE_SCHEMA_VERSIONS = void 0;
|
|
617
|
+
exports.parseCatalogReleaseState = parseCatalogReleaseState;
|
|
615
618
|
var wire_identity_1 = require_wire_identity();
|
|
616
619
|
exports.CATALOG_RELEASE_SCHEMA_VERSIONS = [
|
|
617
620
|
wire_identity_1.CATALOG_RELEASE_SCHEMA_V1
|
|
618
621
|
];
|
|
619
622
|
exports.CATALOG_ACTION_ARTIFACT_SCHEMA_VERSIONS = [
|
|
620
|
-
wire_identity_1.CATALOG_ACTION_ARTIFACT_SCHEMA_V1
|
|
623
|
+
wire_identity_1.CATALOG_ACTION_ARTIFACT_SCHEMA_V1,
|
|
624
|
+
wire_identity_1.CATALOG_ACTION_ARTIFACT_SCHEMA_V2
|
|
621
625
|
];
|
|
622
626
|
exports.ARTIFACT_REPOSITORY_PATTERN = /^[a-z0-9][a-z0-9.-]*(:[0-9]+)?(\/[a-z0-9][a-z0-9._-]*)+$/;
|
|
623
627
|
exports.ARTIFACT_DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
628
|
+
exports.CATALOG_SYNC_RUN_OUTCOMES = [
|
|
629
|
+
"applied",
|
|
630
|
+
"refused",
|
|
631
|
+
"superseded"
|
|
632
|
+
];
|
|
633
|
+
exports.CATALOG_SYNC_SOURCES = [
|
|
634
|
+
"directory",
|
|
635
|
+
"release"
|
|
636
|
+
];
|
|
637
|
+
exports.CATALOG_SYNC_INTERVAL_MINUTES = 15;
|
|
638
|
+
exports.CATALOG_SYNC_STALE_AFTER_MINUTES = exports.CATALOG_SYNC_INTERVAL_MINUTES * 2;
|
|
639
|
+
var CatalogReleaseStateError = class CatalogReleaseStateError extends Error {
|
|
640
|
+
static {
|
|
641
|
+
__name(this, "CatalogReleaseStateError");
|
|
642
|
+
}
|
|
643
|
+
constructor(message) {
|
|
644
|
+
super(message);
|
|
645
|
+
this.name = "CatalogReleaseStateError";
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
exports.CatalogReleaseStateError = CatalogReleaseStateError;
|
|
649
|
+
function stateObject(path, value) {
|
|
650
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
651
|
+
throw new CatalogReleaseStateError(`${path} is not an object.`);
|
|
652
|
+
}
|
|
653
|
+
return value;
|
|
654
|
+
}
|
|
655
|
+
__name(stateObject, "stateObject");
|
|
656
|
+
function stateString(path, value, pattern, expected = "a non-empty string") {
|
|
657
|
+
if (typeof value !== "string" || value === "" || pattern !== void 0 && !pattern.test(value)) {
|
|
658
|
+
throw new CatalogReleaseStateError(`${path} is ${JSON.stringify(value)}, not ${expected}.`);
|
|
659
|
+
}
|
|
660
|
+
return value;
|
|
661
|
+
}
|
|
662
|
+
__name(stateString, "stateString");
|
|
663
|
+
function stateInstant(path, value) {
|
|
664
|
+
const text = stateString(path, value);
|
|
665
|
+
if (Number.isNaN(Date.parse(text))) {
|
|
666
|
+
throw new CatalogReleaseStateError(`${path} is "${text}", which is not a timestamp.`);
|
|
667
|
+
}
|
|
668
|
+
return text;
|
|
669
|
+
}
|
|
670
|
+
__name(stateInstant, "stateInstant");
|
|
671
|
+
var orNull = /* @__PURE__ */ __name((value, read) => value === null ? null : read(value), "orNull");
|
|
672
|
+
function stateMember(path, value, members) {
|
|
673
|
+
if (typeof value === "string" && members.includes(value)) return value;
|
|
674
|
+
throw new CatalogReleaseStateError(`${path} is ${JSON.stringify(value)}; this build reads ${members.join(", ")}.`);
|
|
675
|
+
}
|
|
676
|
+
__name(stateMember, "stateMember");
|
|
677
|
+
function parseSyncRun(value) {
|
|
678
|
+
const run3 = stateObject("lastSync", value);
|
|
679
|
+
const source = stateMember("lastSync.source", run3.source, exports.CATALOG_SYNC_SOURCES);
|
|
680
|
+
const release = orNull(run3.release, (raw) => {
|
|
681
|
+
const fields = stateObject("lastSync.release", raw);
|
|
682
|
+
return {
|
|
683
|
+
artifactRef: stateString("lastSync.release.artifactRef", fields.artifactRef, exports.ARTIFACT_REPOSITORY_PATTERN, "a registry repository"),
|
|
684
|
+
digest: stateString("lastSync.release.digest", fields.digest, exports.ARTIFACT_DIGEST_PATTERN, "a sha256 digest"),
|
|
685
|
+
version: orNull(fields.version, (label) => stateString("lastSync.release.version", label))
|
|
686
|
+
};
|
|
687
|
+
});
|
|
688
|
+
if (source === "release" !== (release !== null)) {
|
|
689
|
+
throw new CatalogReleaseStateError(`lastSync.source is "${source}" and lastSync.release is ${release === null ? "null" : "set"}; a run names a release exactly when a release declared it.`);
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
startedAt: stateInstant("lastSync.startedAt", run3.startedAt),
|
|
693
|
+
finishedAt: stateInstant("lastSync.finishedAt", run3.finishedAt),
|
|
694
|
+
imageTag: orNull(run3.imageTag, (tag) => stateString("lastSync.imageTag", tag)),
|
|
695
|
+
source,
|
|
696
|
+
release,
|
|
697
|
+
outcome: stateMember("lastSync.outcome", run3.outcome, exports.CATALOG_SYNC_RUN_OUTCOMES),
|
|
698
|
+
detail: stateString("lastSync.detail", run3.detail)
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
__name(parseSyncRun, "parseSyncRun");
|
|
702
|
+
function parsePinned(value) {
|
|
703
|
+
const pin = stateObject("release", value);
|
|
704
|
+
return {
|
|
705
|
+
artifactRef: stateString("release.artifactRef", pin.artifactRef, exports.ARTIFACT_REPOSITORY_PATTERN, "a registry repository"),
|
|
706
|
+
digest: stateString("release.digest", pin.digest, exports.ARTIFACT_DIGEST_PATTERN, "a sha256 digest"),
|
|
707
|
+
version: stateString("release.version", pin.version),
|
|
708
|
+
provenance: orNull(pin.provenance, (raw) => {
|
|
709
|
+
const fields = stateObject("release.provenance", raw);
|
|
710
|
+
return {
|
|
711
|
+
repository: stateString("release.provenance.repository", fields.repository),
|
|
712
|
+
commit: stateString("release.provenance.commit", fields.commit)
|
|
713
|
+
};
|
|
714
|
+
}),
|
|
715
|
+
pinnedBy: stateString("release.pinnedBy", pin.pinnedBy),
|
|
716
|
+
pinnedByName: orNull(pin.pinnedByName, (name) => stateString("release.pinnedByName", name)),
|
|
717
|
+
pinnedAt: stateInstant("release.pinnedAt", pin.pinnedAt)
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
__name(parsePinned, "parsePinned");
|
|
721
|
+
function parseCatalogReleaseState(value) {
|
|
722
|
+
const state = stateObject("the catalog release state", value);
|
|
723
|
+
for (const field of [
|
|
724
|
+
"release",
|
|
725
|
+
"imageTag",
|
|
726
|
+
"lastSync",
|
|
727
|
+
"liveSince"
|
|
728
|
+
]) {
|
|
729
|
+
if (!(field in state)) throw new CatalogReleaseStateError(`${field} is missing.`);
|
|
730
|
+
}
|
|
731
|
+
const release = orNull(state.release, parsePinned);
|
|
732
|
+
const liveSince = orNull(state.liveSince, (instant) => stateInstant("liveSince", instant));
|
|
733
|
+
if (release === null && liveSince !== null) {
|
|
734
|
+
throw new CatalogReleaseStateError("liveSince is set with nothing pinned; only a pin goes live.");
|
|
735
|
+
}
|
|
736
|
+
return {
|
|
737
|
+
release,
|
|
738
|
+
imageTag: orNull(state.imageTag, (tag) => stateString("imageTag", tag)),
|
|
739
|
+
lastSync: orNull(state.lastSync, parseSyncRun),
|
|
740
|
+
liveSince
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
__name(parseCatalogReleaseState, "parseCatalogReleaseState");
|
|
624
744
|
}
|
|
625
745
|
});
|
|
626
746
|
|
|
@@ -631,12 +751,13 @@ var require_action_repository = __commonJS({
|
|
|
631
751
|
Object.defineProperty(exports, "__esModule", {
|
|
632
752
|
value: true
|
|
633
753
|
});
|
|
634
|
-
exports.ACTION_REPOSITORY_PREFIX = void 0;
|
|
754
|
+
exports.ACTION_SOURCE_REPOSITORY_PREFIX = exports.ACTION_REPOSITORY_PREFIX = void 0;
|
|
635
755
|
exports.actionKeyRefusal = actionKeyRefusal;
|
|
636
756
|
exports.isActionKey = isActionKey;
|
|
637
757
|
exports.actionRepositoryName = actionRepositoryName;
|
|
758
|
+
exports.actionSourceRepository = actionSourceRepository2;
|
|
638
759
|
exports.actionKeyOf = actionKeyOf;
|
|
639
|
-
exports.actionPackageRefusal =
|
|
760
|
+
exports.actionPackageRefusal = actionPackageRefusal4;
|
|
640
761
|
exports.ACTION_REPOSITORY_PREFIX = "action-";
|
|
641
762
|
var WORD = /^[a-z][a-z0-9]*$/;
|
|
642
763
|
var VERB = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*$/;
|
|
@@ -666,6 +787,11 @@ var require_action_repository = __commonJS({
|
|
|
666
787
|
return `${exports.ACTION_REPOSITORY_PREFIX}${provider}-${resource}-${kebab(verb)}`;
|
|
667
788
|
}
|
|
668
789
|
__name(actionRepositoryName, "actionRepositoryName");
|
|
790
|
+
exports.ACTION_SOURCE_REPOSITORY_PREFIX = "https://github.com/runveric/";
|
|
791
|
+
function actionSourceRepository2(key) {
|
|
792
|
+
return `${exports.ACTION_SOURCE_REPOSITORY_PREFIX}${actionRepositoryName(key)}`;
|
|
793
|
+
}
|
|
794
|
+
__name(actionSourceRepository2, "actionSourceRepository");
|
|
669
795
|
function actionKeyOf(name) {
|
|
670
796
|
if (!name.startsWith(exports.ACTION_REPOSITORY_PREFIX)) return null;
|
|
671
797
|
const [provider, resource, first2, ...rest] = name.slice(exports.ACTION_REPOSITORY_PREFIX.length).split("-");
|
|
@@ -675,7 +801,7 @@ var require_action_repository = __commonJS({
|
|
|
675
801
|
return isActionKey(key) && actionRepositoryName(key) === name ? key : null;
|
|
676
802
|
}
|
|
677
803
|
__name(actionKeyOf, "actionKeyOf");
|
|
678
|
-
function
|
|
804
|
+
function actionPackageRefusal4(key, artifactRef) {
|
|
679
805
|
const keyRefusal = actionKeyRefusal(key);
|
|
680
806
|
if (keyRefusal !== null) return `${keyRefusal} No package can carry it.`;
|
|
681
807
|
const cut = artifactRef.lastIndexOf("/");
|
|
@@ -684,7 +810,7 @@ var require_action_repository = __commonJS({
|
|
|
684
810
|
if (named === expected) return null;
|
|
685
811
|
return `action "${key}" is published only from a package named "${expected}" (${artifactRef.slice(0, cut + 1)}${expected}), not "${named}". An action's package carries its key's name, so an artifact cannot claim an identity its package does not carry.`;
|
|
686
812
|
}
|
|
687
|
-
__name(
|
|
813
|
+
__name(actionPackageRefusal4, "actionPackageRefusal");
|
|
688
814
|
}
|
|
689
815
|
});
|
|
690
816
|
|
|
@@ -697,7 +823,7 @@ var require_catalog_release_spec = __commonJS({
|
|
|
697
823
|
});
|
|
698
824
|
exports.CatalogReleaseSpecError = void 0;
|
|
699
825
|
exports.splitArtifactReference = splitArtifactReference;
|
|
700
|
-
exports.parseCatalogReleaseSpec =
|
|
826
|
+
exports.parseCatalogReleaseSpec = parseCatalogReleaseSpec3;
|
|
701
827
|
var CatalogReleaseSpecError = class CatalogReleaseSpecError extends Error {
|
|
702
828
|
static {
|
|
703
829
|
__name(this, "CatalogReleaseSpecError");
|
|
@@ -717,9 +843,9 @@ var require_catalog_release_spec = __commonJS({
|
|
|
717
843
|
};
|
|
718
844
|
}
|
|
719
845
|
__name(splitArtifactReference, "splitArtifactReference");
|
|
720
|
-
var
|
|
721
|
-
function
|
|
722
|
-
if (!
|
|
846
|
+
var isMapping3 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isMapping");
|
|
847
|
+
function parseCatalogReleaseSpec3(value) {
|
|
848
|
+
if (!isMapping3(value)) {
|
|
723
849
|
throw new CatalogReleaseSpecError("release.yaml is not a mapping of `version` and `actions`.");
|
|
724
850
|
}
|
|
725
851
|
const unknown = Object.keys(value).filter((key) => key !== "version" && key !== "actions");
|
|
@@ -730,10 +856,10 @@ var require_catalog_release_spec = __commonJS({
|
|
|
730
856
|
if (typeof version2 !== "string" || version2.trim().length === 0) {
|
|
731
857
|
throw new CatalogReleaseSpecError(`release.yaml's version is ${JSON.stringify(version2 ?? null)}, not a label. Write it as a quoted string \u2014 version: "2026.10.1" \u2014 because YAML reads an unquoted 2026.10 as a number.`);
|
|
732
858
|
}
|
|
733
|
-
if (actions === null || actions === void 0 ||
|
|
859
|
+
if (actions === null || actions === void 0 || isMapping3(actions) && Object.keys(actions).length === 0) {
|
|
734
860
|
throw new CatalogReleaseSpecError("release.yaml declares no action. An empty release is refused: pinned, it would declare a catalog with nothing in it.");
|
|
735
861
|
}
|
|
736
|
-
if (!
|
|
862
|
+
if (!isMapping3(actions)) {
|
|
737
863
|
throw new CatalogReleaseSpecError("release.yaml's actions is not a mapping of action key to <repository>@<digest>.");
|
|
738
864
|
}
|
|
739
865
|
return {
|
|
@@ -750,7 +876,7 @@ var require_catalog_release_spec = __commonJS({
|
|
|
750
876
|
})
|
|
751
877
|
};
|
|
752
878
|
}
|
|
753
|
-
__name(
|
|
879
|
+
__name(parseCatalogReleaseSpec3, "parseCatalogReleaseSpec");
|
|
754
880
|
}
|
|
755
881
|
});
|
|
756
882
|
|
|
@@ -761,7 +887,7 @@ var require_catalog_lock = __commonJS({
|
|
|
761
887
|
Object.defineProperty(exports, "__esModule", {
|
|
762
888
|
value: true
|
|
763
889
|
});
|
|
764
|
-
exports.CatalogLockError = exports.CATALOG_LOCK_FILE = exports.CATALOG_LOCK_SCHEMA_V1 = void 0;
|
|
890
|
+
exports.MANIFEST_SHA256_PATTERN = exports.CatalogLockError = exports.CATALOG_LOCK_ENGINE_EXECUTION = exports.CATALOG_LOCK_FILE = exports.CATALOG_LOCK_SCHEMA_V1 = void 0;
|
|
765
891
|
exports.parseCatalogLock = parseCatalogLock;
|
|
766
892
|
exports.catalogLockText = catalogLockText;
|
|
767
893
|
exports.authoredElsewhere = authoredElsewhere;
|
|
@@ -769,6 +895,7 @@ var require_catalog_lock = __commonJS({
|
|
|
769
895
|
var catalog_release_1 = require_catalog_release();
|
|
770
896
|
exports.CATALOG_LOCK_SCHEMA_V1 = "runveric.catalog-lock/v1";
|
|
771
897
|
exports.CATALOG_LOCK_FILE = "release.lock.json";
|
|
898
|
+
exports.CATALOG_LOCK_ENGINE_EXECUTION = "engine";
|
|
772
899
|
var CatalogLockError = class CatalogLockError extends Error {
|
|
773
900
|
static {
|
|
774
901
|
__name(this, "CatalogLockError");
|
|
@@ -779,7 +906,7 @@ var require_catalog_lock = __commonJS({
|
|
|
779
906
|
}
|
|
780
907
|
};
|
|
781
908
|
exports.CatalogLockError = CatalogLockError;
|
|
782
|
-
|
|
909
|
+
exports.MANIFEST_SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
783
910
|
function objectAt(path, value, keys) {
|
|
784
911
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
785
912
|
throw new CatalogLockError(`${path} is not an object.`);
|
|
@@ -834,7 +961,9 @@ var require_catalog_lock = __commonJS({
|
|
|
834
961
|
"artifactRef",
|
|
835
962
|
"digest",
|
|
836
963
|
"manifestSha256",
|
|
837
|
-
"provenance"
|
|
964
|
+
"provenance",
|
|
965
|
+
"executes",
|
|
966
|
+
"imageDigest"
|
|
838
967
|
]);
|
|
839
968
|
const key = stringAt(`${path}.key`, action.key);
|
|
840
969
|
const artifactRef = stringAt(`${path}.artifactRef`, action.artifactRef, catalog_release_1.ARTIFACT_REPOSITORY_PATTERN, "a registry repository");
|
|
@@ -848,14 +977,24 @@ var require_catalog_lock = __commonJS({
|
|
|
848
977
|
"repository",
|
|
849
978
|
"commit"
|
|
850
979
|
]);
|
|
980
|
+
if (action.executes === void 0 !== (action.imageDigest === void 0)) {
|
|
981
|
+
throw new CatalogLockError(`${path} carries ${action.executes === void 0 ? "imageDigest without executes" : "executes without imageDigest"}; an engine action records both, a built-in neither.`);
|
|
982
|
+
}
|
|
983
|
+
if (action.executes !== void 0 && action.executes !== exports.CATALOG_LOCK_ENGINE_EXECUTION) {
|
|
984
|
+
throw new CatalogLockError(`${path}.executes is ${JSON.stringify(action.executes)}; the one value it takes is "${exports.CATALOG_LOCK_ENGINE_EXECUTION}".`);
|
|
985
|
+
}
|
|
851
986
|
lock.actions.push({
|
|
852
987
|
key,
|
|
853
988
|
artifactRef,
|
|
854
989
|
digest: stringAt(`${path}.digest`, action.digest, catalog_release_1.ARTIFACT_DIGEST_PATTERN, "a sha256 digest"),
|
|
855
|
-
manifestSha256: stringAt(`${path}.manifestSha256`, action.manifestSha256,
|
|
990
|
+
manifestSha256: stringAt(`${path}.manifestSha256`, action.manifestSha256, exports.MANIFEST_SHA256_PATTERN, "64 lowercase hex characters"),
|
|
856
991
|
provenance: {
|
|
857
992
|
repository: stringAt(`${path}.provenance.repository`, provenance2.repository),
|
|
858
993
|
commit: stringAt(`${path}.provenance.commit`, provenance2.commit)
|
|
994
|
+
},
|
|
995
|
+
...action.executes === void 0 ? {} : {
|
|
996
|
+
executes: exports.CATALOG_LOCK_ENGINE_EXECUTION,
|
|
997
|
+
imageDigest: stringAt(`${path}.imageDigest`, action.imageDigest, catalog_release_1.ARTIFACT_DIGEST_PATTERN, "a sha256 digest")
|
|
859
998
|
}
|
|
860
999
|
});
|
|
861
1000
|
});
|
|
@@ -880,6 +1019,10 @@ var require_catalog_lock = __commonJS({
|
|
|
880
1019
|
provenance: {
|
|
881
1020
|
repository: action.provenance.repository,
|
|
882
1021
|
commit: action.provenance.commit
|
|
1022
|
+
},
|
|
1023
|
+
...action.executes === void 0 || action.imageDigest === void 0 ? {} : {
|
|
1024
|
+
executes: action.executes,
|
|
1025
|
+
imageDigest: action.imageDigest
|
|
883
1026
|
}
|
|
884
1027
|
}))
|
|
885
1028
|
};
|
|
@@ -1654,6 +1797,7 @@ var require_validation = __commonJS({
|
|
|
1654
1797
|
exports.isCheckLevel = isCheckLevel;
|
|
1655
1798
|
exports.isRefusalCode = isRefusalCode;
|
|
1656
1799
|
exports.isDecisionCode = isDecisionCode;
|
|
1800
|
+
exports.validationCheckOf = validationCheckOf;
|
|
1657
1801
|
exports.scopeFailureDetail = scopeFailureDetail;
|
|
1658
1802
|
exports.targetsUnavailableFrom = targetsUnavailableFrom;
|
|
1659
1803
|
exports.compareTargets = compareTargets;
|
|
@@ -1796,12 +1940,69 @@ var require_validation = __commonJS({
|
|
|
1796
1940
|
"disk.customerKey",
|
|
1797
1941
|
"disk.customerKeyUnverified",
|
|
1798
1942
|
"disk.guestEncrypted",
|
|
1799
|
-
"disk.noSnapshot"
|
|
1943
|
+
"disk.noSnapshot",
|
|
1944
|
+
// A confidential VM's disk: its snapshot keeps the VM's guest state, region-bound, and restoring
|
|
1945
|
+
// one is unverified (docs/126 §6.6.1) — the operator's call, never a refusal.
|
|
1946
|
+
"disk.confidential"
|
|
1800
1947
|
];
|
|
1801
1948
|
function isDecisionCode(value) {
|
|
1802
1949
|
return typeof value === "string" && exports.DECISION_CODES.includes(value);
|
|
1803
1950
|
}
|
|
1804
1951
|
__name(isDecisionCode, "isDecisionCode");
|
|
1952
|
+
function validationCheckOf(value) {
|
|
1953
|
+
const raw = typeof value === "object" && value !== null ? value : {};
|
|
1954
|
+
const level = raw.level;
|
|
1955
|
+
if (!isCheckLevel(level)) {
|
|
1956
|
+
return {
|
|
1957
|
+
refusal: `A check level of "${String(level)}" is not in the vocabulary.`
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
if (typeof raw.title !== "string" || raw.title.length === 0) {
|
|
1961
|
+
return {
|
|
1962
|
+
refusal: "Every check must carry a title."
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1965
|
+
if (raw.decision !== void 0 && raw.refusal !== void 0) {
|
|
1966
|
+
return {
|
|
1967
|
+
refusal: `A check carrying both a decision ("${String(raw.decision)}") and a refusal ("${String(raw.refusal)}") is not a check any producer of ours can build.`
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1970
|
+
if (raw.decision !== void 0) {
|
|
1971
|
+
if (!isDecisionCode(raw.decision) || level === "info") {
|
|
1972
|
+
return {
|
|
1973
|
+
refusal: `A check's decision of "${String(raw.decision)}" at level "${level}" is not one this channel accepts.`
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
return {
|
|
1977
|
+
check: {
|
|
1978
|
+
level,
|
|
1979
|
+
title: raw.title,
|
|
1980
|
+
decision: raw.decision
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
if (raw.refusal !== void 0) {
|
|
1985
|
+
if (!isRefusalCode(raw.refusal) || level !== "error") {
|
|
1986
|
+
return {
|
|
1987
|
+
refusal: `A check's refusal of "${String(raw.refusal)}" at level "${level}" is not one this channel accepts.`
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
return {
|
|
1991
|
+
check: {
|
|
1992
|
+
level,
|
|
1993
|
+
title: raw.title,
|
|
1994
|
+
refusal: raw.refusal
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
return {
|
|
1999
|
+
check: {
|
|
2000
|
+
level,
|
|
2001
|
+
title: raw.title
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
__name(validationCheckOf, "validationCheckOf");
|
|
1805
2006
|
function scopeFailureDetail(error) {
|
|
1806
2007
|
const raw = error instanceof Error ? error.message : String(error);
|
|
1807
2008
|
const oneLine = raw.replace(/\s+/g, " ").trim().replace(/[.!]+$/, "");
|
|
@@ -1872,7 +2073,7 @@ var require_execution = __commonJS({
|
|
|
1872
2073
|
Object.defineProperty(exports, "__esModule", {
|
|
1873
2074
|
value: true
|
|
1874
2075
|
});
|
|
1875
|
-
exports.ACCEPTING_A_PROVENANCE_IS_NOT_A_CAPABILITY = exports.RUNNER_PACKAGE_RUNTIME_NOT_PINNED = exports.CONNECTOR_UNAVAILABLE_MESSAGE = exports.ACTION_RUNNABILITY_CAUSE_KINDS = exports.EXECUTION_LOG_ACTIVITY_PHRASE = exports.EXECUTION_LOG_CONNECTION_PHRASE = exports.EXECUTION_LOG_STREAM_PHASES = exports.EXECUTION_LOG_ACTIVITIES = exports.targetsValidationCheck = exports.targetSummarySentence = exports.targetSummaryOf = exports.targetSummaryLabel = exports.targetsUnavailableFrom = exports.targetsUnavailable = exports.targetComparisonSentence = exports.targetComparisonLevel = exports.targetComparisonLabel = exports.TARGETS_NOT_COUNTED = exports.TARGETS_NO_SCOPE = exports.TARGET_COUNT_ABSENCES = exports.TARGET_COMPARISON_KINDS = exports.singleTarget = exports.scopeFailureDetail = exports.noTargetsResolved = exports.isTargetCountAbsence = exports.eligibleTargetCount = exports.compareTargets = exports.REFUSAL_CODES = exports.isRefusalCode = exports.isDecisionCode = exports.isCheckLevel = exports.DECISION_CODES = exports.CHECK_LEVELS = exports.SUBSCRIPTION_ID_FIELD_RENAMED = void 0;
|
|
2076
|
+
exports.ACCEPTING_A_PROVENANCE_IS_NOT_A_CAPABILITY = exports.RUNNER_PACKAGE_RUNTIME_NOT_PINNED = exports.CONNECTOR_UNAVAILABLE_MESSAGE = exports.ACTION_RUNNABILITY_CAUSE_KINDS = exports.EXECUTION_LOG_ACTIVITY_PHRASE = exports.EXECUTION_LOG_CONNECTION_PHRASE = exports.EXECUTION_LOG_STREAM_PHASES = exports.EXECUTION_LOG_ACTIVITIES = exports.validationCheckOf = exports.targetsValidationCheck = exports.targetSummarySentence = exports.targetSummaryOf = exports.targetSummaryLabel = exports.targetsUnavailableFrom = exports.targetsUnavailable = exports.targetComparisonSentence = exports.targetComparisonLevel = exports.targetComparisonLabel = exports.TARGETS_NOT_COUNTED = exports.TARGETS_NO_SCOPE = exports.TARGET_COUNT_ABSENCES = exports.TARGET_COMPARISON_KINDS = exports.singleTarget = exports.scopeFailureDetail = exports.noTargetsResolved = exports.isTargetCountAbsence = exports.eligibleTargetCount = exports.compareTargets = exports.REFUSAL_CODES = exports.isRefusalCode = exports.isDecisionCode = exports.isCheckLevel = exports.DECISION_CODES = exports.CHECK_LEVELS = exports.SUBSCRIPTION_ID_FIELD_RENAMED = void 0;
|
|
1876
2077
|
exports.executionLogStreamSentence = executionLogStreamSentence;
|
|
1877
2078
|
exports.actionRunnabilityCopy = actionRunnabilityCopy;
|
|
1878
2079
|
exports.actionRunnabilityHeadline = actionRunnabilityHeadline;
|
|
@@ -2033,6 +2234,12 @@ var require_execution = __commonJS({
|
|
|
2033
2234
|
return validation_1.targetsValidationCheck;
|
|
2034
2235
|
}, "get")
|
|
2035
2236
|
});
|
|
2237
|
+
Object.defineProperty(exports, "validationCheckOf", {
|
|
2238
|
+
enumerable: true,
|
|
2239
|
+
get: /* @__PURE__ */ __name(function() {
|
|
2240
|
+
return validation_1.validationCheckOf;
|
|
2241
|
+
}, "get")
|
|
2242
|
+
});
|
|
2036
2243
|
exports.EXECUTION_LOG_ACTIVITIES = [
|
|
2037
2244
|
"executing",
|
|
2038
2245
|
"queued",
|
|
@@ -2216,11 +2423,15 @@ var require_decisions = __commonJS({
|
|
|
2216
2423
|
Object.defineProperty(exports, "__esModule", {
|
|
2217
2424
|
value: true
|
|
2218
2425
|
});
|
|
2219
|
-
exports.DECISION_ACKNOWLEDGEMENT = void 0;
|
|
2426
|
+
exports.DECISION_ACKNOWLEDGEMENT = exports.TARGET_DISPOSITIONS = exports.UNDECIDED_AT_RUN = void 0;
|
|
2220
2427
|
exports.recordedDecisionsOf = recordedDecisionsOf;
|
|
2428
|
+
exports.settleDecisionChecks = settleDecisionChecks;
|
|
2221
2429
|
exports.raisedDecisionCodes = raisedDecisionCodes;
|
|
2222
2430
|
exports.decisionMismatch = decisionMismatch;
|
|
2223
2431
|
exports.decisionMismatchSentence = decisionMismatchSentence;
|
|
2432
|
+
exports.targetDecisionsMismatchSentence = targetDecisionsMismatchSentence;
|
|
2433
|
+
exports.decisionsMadeAtSubmit = decisionsMadeAtSubmit;
|
|
2434
|
+
exports.isTargetDisposition = isTargetDisposition;
|
|
2224
2435
|
var validation_1 = require_validation();
|
|
2225
2436
|
function recordedDecisionsOf(stored) {
|
|
2226
2437
|
if (!Array.isArray(stored)) return [];
|
|
@@ -2241,6 +2452,22 @@ var require_decisions = __commonJS({
|
|
|
2241
2452
|
return read;
|
|
2242
2453
|
}
|
|
2243
2454
|
__name(recordedDecisionsOf, "recordedDecisionsOf");
|
|
2455
|
+
exports.UNDECIDED_AT_RUN = "Nobody acknowledged this before the run, so it was not acted on.";
|
|
2456
|
+
function settleDecisionChecks(checks, inHand) {
|
|
2457
|
+
if (inHand.phase === "plan") return [
|
|
2458
|
+
...checks
|
|
2459
|
+
];
|
|
2460
|
+
return checks.map((check) => {
|
|
2461
|
+
if (!check.decision || check.level === "error") return check;
|
|
2462
|
+
if (inHand.recorded.some((decision) => decision.code === check.decision)) return check;
|
|
2463
|
+
return {
|
|
2464
|
+
...check,
|
|
2465
|
+
level: "error",
|
|
2466
|
+
title: `${check.title} ${exports.UNDECIDED_AT_RUN}`
|
|
2467
|
+
};
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
__name(settleDecisionChecks, "settleDecisionChecks");
|
|
2244
2471
|
function raisedDecisionCodes(checks) {
|
|
2245
2472
|
const raised = [];
|
|
2246
2473
|
for (const check of checks) {
|
|
@@ -2258,27 +2485,57 @@ var require_decisions = __commonJS({
|
|
|
2258
2485
|
};
|
|
2259
2486
|
}
|
|
2260
2487
|
__name(decisionMismatch, "decisionMismatch");
|
|
2261
|
-
function decisionMismatchSentence(mismatch) {
|
|
2488
|
+
function decisionMismatchSentence(mismatch, checks = []) {
|
|
2489
|
+
return `This run was not submitted: the checks were run again at submit, and they no longer match what was acknowledged. ${mismatchParts(mismatch, checks).join(" ")} Review the plan and submit again.`;
|
|
2490
|
+
}
|
|
2491
|
+
__name(decisionMismatchSentence, "decisionMismatchSentence");
|
|
2492
|
+
function targetDecisionsMismatchSentence(mismatches) {
|
|
2493
|
+
const parts = mismatches.map((target) => target.unknown ? `${target.label}: no longer one of this step's targets.` : `${target.label}: ${mismatchParts(target, target.checks).join(" ")}`);
|
|
2494
|
+
const count = mismatches.length;
|
|
2495
|
+
return `This run was not started: the checks were run again, and for ${count} ${count === 1 ? "target" : "targets"} they no longer match what was decided. ${parts.join(" ")} Review the plan and start the run again.`;
|
|
2496
|
+
}
|
|
2497
|
+
__name(targetDecisionsMismatchSentence, "targetDecisionsMismatchSentence");
|
|
2498
|
+
function mismatchParts(mismatch, checks) {
|
|
2262
2499
|
const parts = [];
|
|
2263
|
-
|
|
2264
|
-
|
|
2500
|
+
for (const code of mismatch.unacknowledged) {
|
|
2501
|
+
const sentence = checks.find((check) => check.decision === code)?.title ?? exports.DECISION_ACKNOWLEDGEMENT[code];
|
|
2502
|
+
parts.push(`Not acknowledged: ${withStop(sentence)}`);
|
|
2265
2503
|
}
|
|
2266
|
-
|
|
2267
|
-
parts.push(
|
|
2504
|
+
for (const code of mismatch.notRaised) {
|
|
2505
|
+
parts.push(`Acknowledged, but no longer raised: \u201C${exports.DECISION_ACKNOWLEDGEMENT[code]}\u201D.`);
|
|
2268
2506
|
}
|
|
2269
|
-
return
|
|
2507
|
+
return parts;
|
|
2270
2508
|
}
|
|
2271
|
-
__name(
|
|
2272
|
-
function
|
|
2273
|
-
return codes.map((code) =>
|
|
2509
|
+
__name(mismatchParts, "mismatchParts");
|
|
2510
|
+
function decisionsMadeAtSubmit(codes, by, at) {
|
|
2511
|
+
return codes.map((code) => ({
|
|
2512
|
+
code,
|
|
2513
|
+
acknowledgedBy: by,
|
|
2514
|
+
acknowledgedAt: at.toISOString()
|
|
2515
|
+
}));
|
|
2516
|
+
}
|
|
2517
|
+
__name(decisionsMadeAtSubmit, "decisionsMadeAtSubmit");
|
|
2518
|
+
exports.TARGET_DISPOSITIONS = [
|
|
2519
|
+
"ready",
|
|
2520
|
+
"left_out",
|
|
2521
|
+
"refused"
|
|
2522
|
+
];
|
|
2523
|
+
function isTargetDisposition(value) {
|
|
2524
|
+
return typeof value === "string" && exports.TARGET_DISPOSITIONS.includes(value);
|
|
2525
|
+
}
|
|
2526
|
+
__name(isTargetDisposition, "isTargetDisposition");
|
|
2527
|
+
function withStop(sentence) {
|
|
2528
|
+
const trimmed = sentence.trim();
|
|
2529
|
+
return /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
2274
2530
|
}
|
|
2275
|
-
__name(
|
|
2531
|
+
__name(withStop, "withStop");
|
|
2276
2532
|
exports.DECISION_ACKNOWLEDGEMENT = {
|
|
2277
2533
|
"disk.recentlyDetached": "Delete it even though it was detached recently",
|
|
2278
2534
|
"disk.customerKey": "Delete it \u2014 restoring later depends on this key staying enabled",
|
|
2279
2535
|
"disk.customerKeyUnverified": "Delete it without confirmation that the key is enabled",
|
|
2280
2536
|
"disk.guestEncrypted": "Delete it \u2014 restoring later depends on the guest's encryption secrets",
|
|
2281
|
-
"disk.noSnapshot": "Delete it with no snapshot \u2014 this cannot be undone"
|
|
2537
|
+
"disk.noSnapshot": "Delete it with no snapshot \u2014 this cannot be undone",
|
|
2538
|
+
"disk.confidential": "Delete it, accepting that restoring a confidential VM disk is not verified"
|
|
2282
2539
|
};
|
|
2283
2540
|
}
|
|
2284
2541
|
});
|
|
@@ -2642,8 +2899,59 @@ var require_governance = __commonJS({
|
|
|
2642
2899
|
value: true
|
|
2643
2900
|
});
|
|
2644
2901
|
exports.ANY_POLICY_MATCH = void 0;
|
|
2902
|
+
exports.approvalAssessmentOf = approvalAssessmentOf;
|
|
2903
|
+
exports.planAssessmentOf = planAssessmentOf;
|
|
2645
2904
|
exports.approvalOutcome = approvalOutcome;
|
|
2646
2905
|
exports.policyScopeSentence = policyScopeSentence;
|
|
2906
|
+
var decisions_1 = require_decisions();
|
|
2907
|
+
function approvalAssessmentOf(checks, decided) {
|
|
2908
|
+
const assessment = {
|
|
2909
|
+
facts: [],
|
|
2910
|
+
warnings: [],
|
|
2911
|
+
decisions: []
|
|
2912
|
+
};
|
|
2913
|
+
for (const check of checks) {
|
|
2914
|
+
if (check.decision) {
|
|
2915
|
+
const answer = decided.find((decision) => decision.code === check.decision);
|
|
2916
|
+
if (answer) assessment.decisions.push({
|
|
2917
|
+
...answer,
|
|
2918
|
+
title: check.title
|
|
2919
|
+
});
|
|
2920
|
+
} else if (check.level === "warn") {
|
|
2921
|
+
assessment.warnings.push(check.title);
|
|
2922
|
+
} else if (check.level === "info") {
|
|
2923
|
+
assessment.facts.push(check.title);
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
return assessment;
|
|
2927
|
+
}
|
|
2928
|
+
__name(approvalAssessmentOf, "approvalAssessmentOf");
|
|
2929
|
+
function planAssessmentOf(value) {
|
|
2930
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
2931
|
+
const a = value;
|
|
2932
|
+
if (!Array.isArray(a.facts) || !Array.isArray(a.warnings) || !Array.isArray(a.decisions)) {
|
|
2933
|
+
return null;
|
|
2934
|
+
}
|
|
2935
|
+
const decisions = [];
|
|
2936
|
+
for (const entry of a.decisions) {
|
|
2937
|
+
const [decision] = (0, decisions_1.recordedDecisionsOf)([
|
|
2938
|
+
entry
|
|
2939
|
+
]);
|
|
2940
|
+
const title = typeof entry === "object" && entry !== null ? entry.title : null;
|
|
2941
|
+
if (!decision || typeof title !== "string") return null;
|
|
2942
|
+
decisions.push({
|
|
2943
|
+
...decision,
|
|
2944
|
+
title
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2947
|
+
const strings = /* @__PURE__ */ __name((list) => list.filter((item) => typeof item === "string"), "strings");
|
|
2948
|
+
return {
|
|
2949
|
+
facts: strings(a.facts),
|
|
2950
|
+
warnings: strings(a.warnings),
|
|
2951
|
+
decisions
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2954
|
+
__name(planAssessmentOf, "planAssessmentOf");
|
|
2647
2955
|
exports.ANY_POLICY_MATCH = {
|
|
2648
2956
|
environments: [],
|
|
2649
2957
|
riskLevels: [],
|
|
@@ -2754,7 +3062,10 @@ var require_operations = __commonJS({
|
|
|
2754
3062
|
Object.defineProperty(exports, "__esModule", {
|
|
2755
3063
|
value: true
|
|
2756
3064
|
});
|
|
2757
|
-
exports.OPERATION_RUN_TARGET_STATUSES = exports.OPERATION_RUN_STEP_STATUSES = exports.OPERATION_RUN_STATUSES = exports.STEP_FAILURE_POLICIES = exports.OPERATION_STEP_KINDS = exports.DRY_RUN_OUTCOMES = exports.OPERATION_VERIFICATION_LIFECYCLES = exports.OPERATION_HEALTH_STATES = exports.OPERATION_LIFECYCLES = void 0;
|
|
3065
|
+
exports.PREVIEW_UNCHECKED_SENTENCE = exports.PREVIEW_UNCHECKED_REASONS = exports.OPERATION_RUN_TARGET_STATUSES = exports.OPERATION_RUN_STEP_STATUSES = exports.OPERATION_RUN_STATUSES = exports.STEP_FAILURE_POLICIES = exports.OPERATION_STEP_KINDS = exports.DRY_RUN_OUTCOMES = exports.OPERATION_VERIFICATION_LIFECYCLES = exports.OPERATION_HEALTH_STATES = exports.OPERATION_LIFECYCLES = void 0;
|
|
3066
|
+
exports.targetPlanOf = targetPlanOf;
|
|
3067
|
+
var governance_1 = require_governance();
|
|
3068
|
+
var decisions_1 = require_decisions();
|
|
2758
3069
|
exports.OPERATION_LIFECYCLES = [
|
|
2759
3070
|
"draft",
|
|
2760
3071
|
"published",
|
|
@@ -2821,6 +3132,35 @@ var require_operations = __commonJS({
|
|
|
2821
3132
|
"rolled_back",
|
|
2822
3133
|
"rollback_failed"
|
|
2823
3134
|
];
|
|
3135
|
+
function targetPlanOf(stored) {
|
|
3136
|
+
if (!Array.isArray(stored)) return null;
|
|
3137
|
+
const plan = [];
|
|
3138
|
+
for (const entry of stored) {
|
|
3139
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
3140
|
+
const { ref, label, disposition, decisions, assessment, refusal } = entry;
|
|
3141
|
+
if (typeof ref !== "string" || ref.length === 0) continue;
|
|
3142
|
+
if (typeof label !== "string" || !(0, decisions_1.isTargetDisposition)(disposition)) continue;
|
|
3143
|
+
if (refusal !== null && typeof refusal !== "string") continue;
|
|
3144
|
+
plan.push({
|
|
3145
|
+
ref,
|
|
3146
|
+
label,
|
|
3147
|
+
disposition,
|
|
3148
|
+
decisions: (0, decisions_1.recordedDecisionsOf)(decisions),
|
|
3149
|
+
assessment: (0, governance_1.planAssessmentOf)(assessment),
|
|
3150
|
+
refusal: refusal ?? null
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
return plan;
|
|
3154
|
+
}
|
|
3155
|
+
__name(targetPlanOf, "targetPlanOf");
|
|
3156
|
+
exports.PREVIEW_UNCHECKED_REASONS = [
|
|
3157
|
+
"depends_on_earlier_output",
|
|
3158
|
+
"connector_plans_no_checks"
|
|
3159
|
+
];
|
|
3160
|
+
exports.PREVIEW_UNCHECKED_SENTENCE = {
|
|
3161
|
+
depends_on_earlier_output: "Not checked before the run: this step's parameters come from an earlier step's outputs, which exist only once that step has run. Each target is checked when its execution is submitted, and a target that would need a decision is not acted on.",
|
|
3162
|
+
connector_plans_no_checks: "This action runs no checks of its own before the run."
|
|
3163
|
+
};
|
|
2824
3164
|
}
|
|
2825
3165
|
});
|
|
2826
3166
|
|
|
@@ -2943,7 +3283,7 @@ var require_package_execution = __commonJS({
|
|
|
2943
3283
|
Object.defineProperty(exports, "__esModule", {
|
|
2944
3284
|
value: true
|
|
2945
3285
|
});
|
|
2946
|
-
exports.PACKAGE_CONTAINER_ENV = exports.PACKAGE_PHASES = void 0;
|
|
3286
|
+
exports.RUN_TOKEN_REJECTED = exports.RUN_TOKEN_HEADER = exports.PACKAGE_RUNNER_ENTRYPOINT = exports.PACKAGE_CONTAINER_ENV = exports.PACKAGE_PHASES = void 0;
|
|
2947
3287
|
exports.PACKAGE_PHASES = [
|
|
2948
3288
|
"validate",
|
|
2949
3289
|
"run",
|
|
@@ -2965,6 +3305,11 @@ var require_package_execution = __commonJS({
|
|
|
2965
3305
|
egressControlUrl: "RUNVERIC_EGRESS_CONTROL_URL",
|
|
2966
3306
|
egressControlToken: "RUNVERIC_EGRESS_CONTROL_TOKEN"
|
|
2967
3307
|
};
|
|
3308
|
+
exports.PACKAGE_RUNNER_ENTRYPOINT = [
|
|
3309
|
+
"/opt/runveric/runner/launch.sh"
|
|
3310
|
+
];
|
|
3311
|
+
exports.RUN_TOKEN_HEADER = "x-runveric-run-token";
|
|
3312
|
+
exports.RUN_TOKEN_REJECTED = "This run token is not valid for this execution.";
|
|
2968
3313
|
}
|
|
2969
3314
|
});
|
|
2970
3315
|
|
|
@@ -3215,6 +3560,803 @@ var require_runners = __commonJS({
|
|
|
3215
3560
|
}
|
|
3216
3561
|
});
|
|
3217
3562
|
|
|
3563
|
+
// ../contracts/dist/scoped-credential.js
|
|
3564
|
+
var require_scoped_credential = __commonJS({
|
|
3565
|
+
"../contracts/dist/scoped-credential.js"(exports) {
|
|
3566
|
+
"use strict";
|
|
3567
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3568
|
+
value: true
|
|
3569
|
+
});
|
|
3570
|
+
exports.RunnerStepCredentialExpiredError = exports.RunnerStepCredentialError = exports.STEP_CREDENTIAL_FAILURE = exports.ENGINE_ACTION_TOKEN_HOLDER = exports.RUNNER_STEP_TOKEN_HOLDER = exports.StaticScopedCredential = void 0;
|
|
3571
|
+
var StaticScopedCredential = class StaticScopedCredential {
|
|
3572
|
+
static {
|
|
3573
|
+
__name(this, "StaticScopedCredential");
|
|
3574
|
+
}
|
|
3575
|
+
now;
|
|
3576
|
+
holder;
|
|
3577
|
+
byScope;
|
|
3578
|
+
constructor(tokens2, now = Date.now, holder = exports.RUNNER_STEP_TOKEN_HOLDER) {
|
|
3579
|
+
this.now = now;
|
|
3580
|
+
this.holder = holder;
|
|
3581
|
+
this.byScope = new Map(tokens2.map((token2) => [
|
|
3582
|
+
token2.scope,
|
|
3583
|
+
token2
|
|
3584
|
+
]));
|
|
3585
|
+
}
|
|
3586
|
+
async getToken(scopes) {
|
|
3587
|
+
const requested = typeof scopes === "string" ? [
|
|
3588
|
+
scopes
|
|
3589
|
+
] : scopes;
|
|
3590
|
+
for (const scope of requested) {
|
|
3591
|
+
const token2 = this.byScope.get(scope);
|
|
3592
|
+
if (token2) {
|
|
3593
|
+
if (token2.expiresOnTimestamp <= this.now()) {
|
|
3594
|
+
throw new RunnerStepCredentialExpiredError(scope, token2.expiresOnTimestamp, this.now(), this.holder);
|
|
3595
|
+
}
|
|
3596
|
+
return {
|
|
3597
|
+
token: token2.token,
|
|
3598
|
+
expiresOnTimestamp: token2.expiresOnTimestamp
|
|
3599
|
+
};
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
throw new RunnerStepCredentialError(requested, [
|
|
3603
|
+
...this.byScope.keys()
|
|
3604
|
+
], this.holder);
|
|
3605
|
+
}
|
|
3606
|
+
};
|
|
3607
|
+
exports.StaticScopedCredential = StaticScopedCredential;
|
|
3608
|
+
exports.RUNNER_STEP_TOKEN_HOLDER = {
|
|
3609
|
+
noun: "step",
|
|
3610
|
+
whereDeclared: "The channel mints exactly what a connector's azureAudiences declares, so this connector reaches an Azure resource it does not say it reaches.",
|
|
3611
|
+
whyNoMore: "A step container is handed minted bytes and nothing it can use to get another, so the step ran longer than its own credential and cannot continue."
|
|
3612
|
+
};
|
|
3613
|
+
exports.ENGINE_ACTION_TOKEN_HOLDER = {
|
|
3614
|
+
noun: "action",
|
|
3615
|
+
whereDeclared: "The engine mints exactly the audiences an action's manifest declares in execution.audiences, so this action reaches an Azure resource it does not say it reaches.",
|
|
3616
|
+
whyNoMore: "An action is handed minted bytes and nothing it can use to get another, so it ran longer than its own credential and cannot continue."
|
|
3617
|
+
};
|
|
3618
|
+
exports.STEP_CREDENTIAL_FAILURE = "runvericStepCredentialFailure";
|
|
3619
|
+
var RunnerStepCredentialError = class RunnerStepCredentialError extends Error {
|
|
3620
|
+
static {
|
|
3621
|
+
__name(this, "RunnerStepCredentialError");
|
|
3622
|
+
}
|
|
3623
|
+
constructor(requested, available, holder = exports.RUNNER_STEP_TOKEN_HOLDER) {
|
|
3624
|
+
super(`This ${holder.noun} was authorized for ${available.length > 0 ? available.map(quote).join(", ") : "no scopes"} and asked for ${requested.map(quote).join(", ")}. ${holder.whereDeclared}`);
|
|
3625
|
+
this.name = "RunnerStepCredentialError";
|
|
3626
|
+
}
|
|
3627
|
+
/** Not a fact about the resource — see {@link STEP_CREDENTIAL_FAILURE}. */
|
|
3628
|
+
[exports.STEP_CREDENTIAL_FAILURE] = true;
|
|
3629
|
+
};
|
|
3630
|
+
exports.RunnerStepCredentialError = RunnerStepCredentialError;
|
|
3631
|
+
var RunnerStepCredentialExpiredError = class RunnerStepCredentialExpiredError extends Error {
|
|
3632
|
+
static {
|
|
3633
|
+
__name(this, "RunnerStepCredentialExpiredError");
|
|
3634
|
+
}
|
|
3635
|
+
constructor(scope, expiresOnTimestamp, now, holder = exports.RUNNER_STEP_TOKEN_HOLDER) {
|
|
3636
|
+
super(`This ${holder.noun}'s token for ${quote(scope)} expired ${Math.round((now - expiresOnTimestamp) / 1e3)}s ago, at ${new Date(expiresOnTimestamp).toISOString()}. ${holder.whyNoMore}`);
|
|
3637
|
+
this.name = "RunnerStepCredentialExpiredError";
|
|
3638
|
+
}
|
|
3639
|
+
/** Not a fact about the resource — see {@link STEP_CREDENTIAL_FAILURE}. */
|
|
3640
|
+
[exports.STEP_CREDENTIAL_FAILURE] = true;
|
|
3641
|
+
};
|
|
3642
|
+
exports.RunnerStepCredentialExpiredError = RunnerStepCredentialExpiredError;
|
|
3643
|
+
function quote(scope) {
|
|
3644
|
+
return `"${scope}"`;
|
|
3645
|
+
}
|
|
3646
|
+
__name(quote, "quote");
|
|
3647
|
+
}
|
|
3648
|
+
});
|
|
3649
|
+
|
|
3650
|
+
// ../contracts/dist/action-protocol.js
|
|
3651
|
+
var require_action_protocol = __commonJS({
|
|
3652
|
+
"../contracts/dist/action-protocol.js"(exports) {
|
|
3653
|
+
"use strict";
|
|
3654
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3655
|
+
value: true
|
|
3656
|
+
});
|
|
3657
|
+
exports.ActionProtocolError = exports.JWT_SHAPE = exports.REDACTED_SECRET = exports.ENGINE_RUN_ROUTES = exports.ACTION_PROBE_ENV = exports.ACTION_RUNTIME_PROBE_FLAG = exports.ACTION_CONTAINER_ENV = exports.MAX_PLAN_VALIDATE_TARGETS = exports.ACTION_PROTOCOL_LIMITS = exports.ACTION_EXECUTION_KINDS = exports.ENGINE_CONNECTOR_KEY = exports.ACTION_CONTRACTS = void 0;
|
|
3658
|
+
exports.isActionContract = isActionContract;
|
|
3659
|
+
exports.engineRunUrl = engineRunUrl;
|
|
3660
|
+
exports.actionAudienceRefusal = actionAudienceRefusal;
|
|
3661
|
+
exports.actionTokenScope = actionTokenScope;
|
|
3662
|
+
exports.redactSecrets = redactSecrets;
|
|
3663
|
+
exports.redactJwtShaped = redactJwtShaped;
|
|
3664
|
+
exports.carriesJwtShaped = carriesJwtShaped;
|
|
3665
|
+
exports.jsonByteLength = jsonByteLength;
|
|
3666
|
+
exports.parseActionInvocation = parseActionInvocation;
|
|
3667
|
+
exports.parseActionEvent = parseActionEvent;
|
|
3668
|
+
exports.tooManyEvents = tooManyEvents;
|
|
3669
|
+
exports.parseActionCheckpoint = parseActionCheckpoint;
|
|
3670
|
+
exports.parseCheckpointAck = parseCheckpointAck;
|
|
3671
|
+
exports.parseActionReport = parseActionReport;
|
|
3672
|
+
var wire_identity_1 = require_wire_identity();
|
|
3673
|
+
var package_execution_1 = require_package_execution();
|
|
3674
|
+
var validation_1 = require_validation();
|
|
3675
|
+
exports.ACTION_CONTRACTS = [
|
|
3676
|
+
wire_identity_1.ACTION_PROTOCOL_V1
|
|
3677
|
+
];
|
|
3678
|
+
function isActionContract(value) {
|
|
3679
|
+
return typeof value === "string" && exports.ACTION_CONTRACTS.includes(value);
|
|
3680
|
+
}
|
|
3681
|
+
__name(isActionContract, "isActionContract");
|
|
3682
|
+
exports.ENGINE_CONNECTOR_KEY = "runveric.engine";
|
|
3683
|
+
exports.ACTION_EXECUTION_KINDS = [
|
|
3684
|
+
"engine"
|
|
3685
|
+
];
|
|
3686
|
+
exports.ACTION_PROTOCOL_LIMITS = {
|
|
3687
|
+
maxEvents: 500,
|
|
3688
|
+
maxEventBytes: 2048,
|
|
3689
|
+
maxReportBytes: 262144,
|
|
3690
|
+
maxRestorePointBytes: 65536
|
|
3691
|
+
};
|
|
3692
|
+
exports.MAX_PLAN_VALIDATE_TARGETS = 200;
|
|
3693
|
+
exports.ACTION_CONTAINER_ENV = {
|
|
3694
|
+
runToken: "RUNVERIC_ACTION_RUN_TOKEN",
|
|
3695
|
+
callbackBaseUrl: "RUNVERIC_ACTION_CALLBACK_BASE_URL",
|
|
3696
|
+
runId: "RUNVERIC_ACTION_RUN_ID",
|
|
3697
|
+
imageDigest: "RUNVERIC_ACTION_IMAGE_DIGEST"
|
|
3698
|
+
};
|
|
3699
|
+
exports.ACTION_RUNTIME_PROBE_FLAG = "--probe";
|
|
3700
|
+
exports.ACTION_PROBE_ENV = {
|
|
3701
|
+
identities: "RUNVERIC_PROBE_IDENTITIES"
|
|
3702
|
+
};
|
|
3703
|
+
exports.ENGINE_RUN_ROUTES = {
|
|
3704
|
+
base: "internal/engine-runs",
|
|
3705
|
+
invocation: "invocation",
|
|
3706
|
+
events: "events",
|
|
3707
|
+
checkpoint: "checkpoint",
|
|
3708
|
+
report: "report"
|
|
3709
|
+
};
|
|
3710
|
+
function engineRunUrl(callbackBaseUrl, runId, message) {
|
|
3711
|
+
const origin2 = callbackBaseUrl.replace(/\/+$/, "");
|
|
3712
|
+
return `${origin2}/${exports.ENGINE_RUN_ROUTES.base}/${encodeURIComponent(runId)}/${exports.ENGINE_RUN_ROUTES[message]}`;
|
|
3713
|
+
}
|
|
3714
|
+
__name(engineRunUrl, "engineRunUrl");
|
|
3715
|
+
function actionAudienceRefusal(value) {
|
|
3716
|
+
if (typeof value === "string" && AUDIENCE_ORIGIN.test(value)) return null;
|
|
3717
|
+
return `"${String(value)}" is not an audience. An audience is the https origin of the resource a token is for \u2014 lowercase, with no port, path or trailing slash, e.g. "https://management.azure.com".`;
|
|
3718
|
+
}
|
|
3719
|
+
__name(actionAudienceRefusal, "actionAudienceRefusal");
|
|
3720
|
+
var AUDIENCE_ORIGIN = /^https:\/\/[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
3721
|
+
function actionTokenScope(audience) {
|
|
3722
|
+
return `${audience}/.default`;
|
|
3723
|
+
}
|
|
3724
|
+
__name(actionTokenScope, "actionTokenScope");
|
|
3725
|
+
exports.REDACTED_SECRET = "[redacted]";
|
|
3726
|
+
function redactSecrets(value, secrets) {
|
|
3727
|
+
const present = secrets.filter((secret) => secret.length > 0);
|
|
3728
|
+
if (present.length === 0) return value;
|
|
3729
|
+
return mapStrings(value, (text) => present.reduce((out, secret) => out.split(secret).join(exports.REDACTED_SECRET), text));
|
|
3730
|
+
}
|
|
3731
|
+
__name(redactSecrets, "redactSecrets");
|
|
3732
|
+
exports.JWT_SHAPE = /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*/;
|
|
3733
|
+
function redactJwtShaped(value) {
|
|
3734
|
+
const everyMatch = new RegExp(exports.JWT_SHAPE.source, "g");
|
|
3735
|
+
return mapStrings(value, (text) => text.replace(everyMatch, exports.REDACTED_SECRET));
|
|
3736
|
+
}
|
|
3737
|
+
__name(redactJwtShaped, "redactJwtShaped");
|
|
3738
|
+
function carriesJwtShaped(value) {
|
|
3739
|
+
let found = false;
|
|
3740
|
+
mapStrings(value, (text) => {
|
|
3741
|
+
found ||= exports.JWT_SHAPE.test(text);
|
|
3742
|
+
return text;
|
|
3743
|
+
});
|
|
3744
|
+
return found;
|
|
3745
|
+
}
|
|
3746
|
+
__name(carriesJwtShaped, "carriesJwtShaped");
|
|
3747
|
+
function mapStrings(value, scrub) {
|
|
3748
|
+
const walk = /* @__PURE__ */ __name((node) => {
|
|
3749
|
+
if (typeof node === "string") return scrub(node);
|
|
3750
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
3751
|
+
if (node !== null && typeof node === "object") {
|
|
3752
|
+
return Object.fromEntries(Object.entries(node).map(([key, item]) => [
|
|
3753
|
+
scrub(key),
|
|
3754
|
+
walk(item)
|
|
3755
|
+
]));
|
|
3756
|
+
}
|
|
3757
|
+
return node;
|
|
3758
|
+
}, "walk");
|
|
3759
|
+
return walk(value);
|
|
3760
|
+
}
|
|
3761
|
+
__name(mapStrings, "mapStrings");
|
|
3762
|
+
function jsonByteLength(value) {
|
|
3763
|
+
const text = JSON.stringify(value) ?? "";
|
|
3764
|
+
let bytes = 0;
|
|
3765
|
+
for (const char of text) {
|
|
3766
|
+
const point = char.codePointAt(0) ?? 0;
|
|
3767
|
+
bytes += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
|
|
3768
|
+
}
|
|
3769
|
+
return bytes;
|
|
3770
|
+
}
|
|
3771
|
+
__name(jsonByteLength, "jsonByteLength");
|
|
3772
|
+
var ActionProtocolError = class ActionProtocolError extends Error {
|
|
3773
|
+
static {
|
|
3774
|
+
__name(this, "ActionProtocolError");
|
|
3775
|
+
}
|
|
3776
|
+
constructor(message) {
|
|
3777
|
+
super(message);
|
|
3778
|
+
this.name = "ActionProtocolError";
|
|
3779
|
+
}
|
|
3780
|
+
};
|
|
3781
|
+
exports.ActionProtocolError = ActionProtocolError;
|
|
3782
|
+
function parseActionInvocation(body) {
|
|
3783
|
+
const raw = objectOf(body, "The invocation");
|
|
3784
|
+
onlyKeys(raw, INVOCATION_KEYS, "The invocation");
|
|
3785
|
+
if (!isActionContract(raw.protocol)) {
|
|
3786
|
+
throw new ActionProtocolError(`The invocation speaks ${String(raw.protocol)}, and this runtime speaks ${exports.ACTION_CONTRACTS.join(", ")}.`);
|
|
3787
|
+
}
|
|
3788
|
+
const phase = raw.phase;
|
|
3789
|
+
if (typeof phase !== "string" || !package_execution_1.PACKAGE_PHASES.includes(phase)) {
|
|
3790
|
+
throw new ActionProtocolError(`An invocation phase of "${String(phase)}" is not in the vocabulary.`);
|
|
3791
|
+
}
|
|
3792
|
+
const actionRaw = objectOf(raw.action, "The invocation's action");
|
|
3793
|
+
onlyKeys(actionRaw, [
|
|
3794
|
+
"key",
|
|
3795
|
+
"version",
|
|
3796
|
+
"image"
|
|
3797
|
+
], "The invocation's action");
|
|
3798
|
+
const action = {
|
|
3799
|
+
key: nonEmpty(actionRaw.key, "The action's key"),
|
|
3800
|
+
version: nonEmpty(actionRaw.version, "The action's version"),
|
|
3801
|
+
image: digestPinned(actionRaw.image)
|
|
3802
|
+
};
|
|
3803
|
+
const executionRaw = objectOf(raw.execution, "The invocation's execution");
|
|
3804
|
+
onlyKeys(executionRaw, [
|
|
3805
|
+
"id",
|
|
3806
|
+
"tenantId",
|
|
3807
|
+
"correlationId",
|
|
3808
|
+
"dryRun"
|
|
3809
|
+
], "The invocation's execution");
|
|
3810
|
+
if (typeof executionRaw.dryRun !== "boolean") {
|
|
3811
|
+
throw new ActionProtocolError("The invocation's execution must say whether it is a dry run.");
|
|
3812
|
+
}
|
|
3813
|
+
const execution = {
|
|
3814
|
+
id: nonEmpty(executionRaw.id, "The execution's id"),
|
|
3815
|
+
tenantId: nonEmpty(executionRaw.tenantId, "The execution's tenant"),
|
|
3816
|
+
correlationId: nonEmpty(executionRaw.correlationId, "The execution's correlation id"),
|
|
3817
|
+
dryRun: executionRaw.dryRun
|
|
3818
|
+
};
|
|
3819
|
+
const limits = parseLimits(raw.limits);
|
|
3820
|
+
const decisions = parseDecisions(raw.decisions);
|
|
3821
|
+
const targets = parseTargets(raw.targets);
|
|
3822
|
+
const credentials = {
|
|
3823
|
+
tokens: parseTokens(objectOf(raw.credentials, "The invocation's credentials"))
|
|
3824
|
+
};
|
|
3825
|
+
const restorePoint = nullableObject(raw.restorePoint, "The invocation's restore point");
|
|
3826
|
+
const priorResult = nullableObject(raw.priorResult, "The invocation's prior result");
|
|
3827
|
+
if (restorePoint !== null && jsonByteLength(restorePoint) > limits.maxRestorePointBytes) {
|
|
3828
|
+
throw new ActionProtocolError(`The invocation's restore point is larger than ${limits.maxRestorePointBytes} bytes.`);
|
|
3829
|
+
}
|
|
3830
|
+
const base = {
|
|
3831
|
+
protocol: raw.protocol,
|
|
3832
|
+
action,
|
|
3833
|
+
execution,
|
|
3834
|
+
targets,
|
|
3835
|
+
credentials,
|
|
3836
|
+
limits
|
|
3837
|
+
};
|
|
3838
|
+
if (phase === "validate") {
|
|
3839
|
+
if (raw.mode !== "plan" && raw.mode !== "run") {
|
|
3840
|
+
throw new ActionProtocolError(`A validate invocation's mode of "${String(raw.mode)}" is not "plan" or "run".`);
|
|
3841
|
+
}
|
|
3842
|
+
if (raw.mode !== decisions.phase) {
|
|
3843
|
+
throw new ActionProtocolError(`A validate invocation in ${raw.mode} mode carries ${decisions.phase}-phase decisions; the two are the same fact.`);
|
|
3844
|
+
}
|
|
3845
|
+
assertTargetCount(targets.length, raw.mode === "plan" ? exports.MAX_PLAN_VALIDATE_TARGETS : 1, `A ${raw.mode}-mode validate`);
|
|
3846
|
+
if (restorePoint !== null || priorResult !== null) {
|
|
3847
|
+
throw new ActionProtocolError("A validate invocation carries no restore point and no prior result.");
|
|
3848
|
+
}
|
|
3849
|
+
return {
|
|
3850
|
+
...base,
|
|
3851
|
+
phase,
|
|
3852
|
+
mode: raw.mode,
|
|
3853
|
+
decisions,
|
|
3854
|
+
restorePoint: null,
|
|
3855
|
+
priorResult: null
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
if (raw.mode !== void 0) {
|
|
3859
|
+
throw new ActionProtocolError(`A ${phase} invocation has no mode \u2014 only a validate is asked in a mode.`);
|
|
3860
|
+
}
|
|
3861
|
+
if (decisions.phase !== "run") {
|
|
3862
|
+
throw new ActionProtocolError(`A ${phase} invocation carries a run's decisions, never a plan's.`);
|
|
3863
|
+
}
|
|
3864
|
+
assertTargetCount(targets.length, 1, `A ${phase}`);
|
|
3865
|
+
if (phase === "run") {
|
|
3866
|
+
if (priorResult !== null) {
|
|
3867
|
+
throw new ActionProtocolError("A run invocation carries no prior result \u2014 only a rollback reads one.");
|
|
3868
|
+
}
|
|
3869
|
+
return {
|
|
3870
|
+
...base,
|
|
3871
|
+
phase,
|
|
3872
|
+
decisions,
|
|
3873
|
+
restorePoint,
|
|
3874
|
+
priorResult: null
|
|
3875
|
+
};
|
|
3876
|
+
}
|
|
3877
|
+
return {
|
|
3878
|
+
...base,
|
|
3879
|
+
phase: "rollback",
|
|
3880
|
+
decisions,
|
|
3881
|
+
restorePoint,
|
|
3882
|
+
priorResult
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
__name(parseActionInvocation, "parseActionInvocation");
|
|
3886
|
+
function parseActionEvent(body, limits, alreadyReceived) {
|
|
3887
|
+
if (alreadyReceived >= limits.maxEvents) throw tooManyEvents(limits);
|
|
3888
|
+
const raw = objectOf(body, "An event");
|
|
3889
|
+
onlyKeys(raw, [
|
|
3890
|
+
"level",
|
|
3891
|
+
"message",
|
|
3892
|
+
"data"
|
|
3893
|
+
], "An event");
|
|
3894
|
+
if (jsonByteLength(raw) > limits.maxEventBytes) {
|
|
3895
|
+
throw new ActionProtocolError(`An event is larger than ${limits.maxEventBytes} bytes.`);
|
|
3896
|
+
}
|
|
3897
|
+
if (typeof raw.level !== "string" || !Object.hasOwn(EVENT_LEVELS, raw.level)) {
|
|
3898
|
+
throw new ActionProtocolError(`An event level of "${String(raw.level)}" is not in the vocabulary.`);
|
|
3899
|
+
}
|
|
3900
|
+
const message = nonEmpty(raw.message, "An event's message");
|
|
3901
|
+
if (raw.data === void 0) return {
|
|
3902
|
+
level: raw.level,
|
|
3903
|
+
message
|
|
3904
|
+
};
|
|
3905
|
+
return {
|
|
3906
|
+
level: raw.level,
|
|
3907
|
+
message,
|
|
3908
|
+
data: jsonObject(raw.data, "An event's data")
|
|
3909
|
+
};
|
|
3910
|
+
}
|
|
3911
|
+
__name(parseActionEvent, "parseActionEvent");
|
|
3912
|
+
function tooManyEvents(limits) {
|
|
3913
|
+
return new ActionProtocolError(`The action sent more than ${limits.maxEvents} events.`);
|
|
3914
|
+
}
|
|
3915
|
+
__name(tooManyEvents, "tooManyEvents");
|
|
3916
|
+
function parseActionCheckpoint(body, limits) {
|
|
3917
|
+
const raw = objectOf(body, "A checkpoint");
|
|
3918
|
+
onlyKeys(raw, [
|
|
3919
|
+
"kind",
|
|
3920
|
+
"record"
|
|
3921
|
+
], "A checkpoint");
|
|
3922
|
+
if (raw.kind !== "restore_point") {
|
|
3923
|
+
throw new ActionProtocolError(`A checkpoint of kind "${String(raw.kind)}" is not one this contract knows.`);
|
|
3924
|
+
}
|
|
3925
|
+
const record = jsonObject(raw.record, "A checkpoint's record");
|
|
3926
|
+
if (jsonByteLength(record) > limits.maxRestorePointBytes) {
|
|
3927
|
+
throw new ActionProtocolError(`A restore point is larger than ${limits.maxRestorePointBytes} bytes.`);
|
|
3928
|
+
}
|
|
3929
|
+
return {
|
|
3930
|
+
kind: "restore_point",
|
|
3931
|
+
record
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3934
|
+
__name(parseActionCheckpoint, "parseActionCheckpoint");
|
|
3935
|
+
function parseCheckpointAck(body) {
|
|
3936
|
+
const raw = objectOf(body, "A checkpoint acknowledgement");
|
|
3937
|
+
onlyKeys(raw, [
|
|
3938
|
+
"acknowledged"
|
|
3939
|
+
], "A checkpoint acknowledgement");
|
|
3940
|
+
if (raw.acknowledged !== true) {
|
|
3941
|
+
throw new ActionProtocolError("The checkpoint was not acknowledged.");
|
|
3942
|
+
}
|
|
3943
|
+
return {
|
|
3944
|
+
acknowledged: true
|
|
3945
|
+
};
|
|
3946
|
+
}
|
|
3947
|
+
__name(parseCheckpointAck, "parseCheckpointAck");
|
|
3948
|
+
function parseActionReport(body, sent) {
|
|
3949
|
+
const raw = objectOf(body, "The report");
|
|
3950
|
+
onlyKeys(raw, [
|
|
3951
|
+
"phase",
|
|
3952
|
+
"checks",
|
|
3953
|
+
"outcome"
|
|
3954
|
+
], "The report");
|
|
3955
|
+
if (jsonByteLength(raw) > sent.limits.maxReportBytes) {
|
|
3956
|
+
throw new ActionProtocolError(`The report is larger than ${sent.limits.maxReportBytes} bytes.`);
|
|
3957
|
+
}
|
|
3958
|
+
if (raw.phase !== sent.phase) {
|
|
3959
|
+
throw new ActionProtocolError(`The report is for phase "${String(raw.phase)}", but this invocation is for "${sent.phase}".`);
|
|
3960
|
+
}
|
|
3961
|
+
if (sent.phase === "validate") {
|
|
3962
|
+
if (raw.checks === void 0 === (raw.outcome === void 0)) {
|
|
3963
|
+
throw new ActionProtocolError("A validate report carries checks, or \u2014 when they could not run \u2014 a failed outcome; exactly one of the two.");
|
|
3964
|
+
}
|
|
3965
|
+
if (raw.outcome !== void 0) {
|
|
3966
|
+
const outcome = parseOutcome(raw.outcome);
|
|
3967
|
+
if (outcome.status !== "failed") {
|
|
3968
|
+
throw new ActionProtocolError(`A validate report's outcome can only say the checks failed to run, never "${outcome.status}" \u2014 the engine decides what checks mean.`);
|
|
3969
|
+
}
|
|
3970
|
+
return {
|
|
3971
|
+
phase: "validate",
|
|
3972
|
+
outcome
|
|
3973
|
+
};
|
|
3974
|
+
}
|
|
3975
|
+
const byRef = objectOf(raw.checks, "A validate report's checks");
|
|
3976
|
+
const expected = new Set(sent.targets.map((target) => target.ref));
|
|
3977
|
+
for (const ref of Object.keys(byRef)) {
|
|
3978
|
+
if (!expected.has(ref)) {
|
|
3979
|
+
throw new ActionProtocolError(`The report answers for "${ref}", which is not one of the targets it was given.`);
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
const checks = sent.targets.map(({ ref }) => {
|
|
3983
|
+
if (!Object.hasOwn(byRef, ref)) {
|
|
3984
|
+
throw new ActionProtocolError(`The report says nothing about "${ref}", one of the targets it was given.`);
|
|
3985
|
+
}
|
|
3986
|
+
const list = byRef[ref];
|
|
3987
|
+
if (!Array.isArray(list)) {
|
|
3988
|
+
throw new ActionProtocolError(`The checks for "${ref}" must be an array.`);
|
|
3989
|
+
}
|
|
3990
|
+
return {
|
|
3991
|
+
ref,
|
|
3992
|
+
checks: list.map((entry) => {
|
|
3993
|
+
const parsed = (0, validation_1.validationCheckOf)(entry);
|
|
3994
|
+
if ("refusal" in parsed) throw new ActionProtocolError(`The checks for "${ref}": ${parsed.refusal}`);
|
|
3995
|
+
return parsed.check;
|
|
3996
|
+
})
|
|
3997
|
+
};
|
|
3998
|
+
});
|
|
3999
|
+
return {
|
|
4000
|
+
phase: "validate",
|
|
4001
|
+
checks
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
if (raw.checks !== void 0) {
|
|
4005
|
+
throw new ActionProtocolError(`A ${sent.phase} report carries an outcome, never checks \u2014 those are the validate phase's answer.`);
|
|
4006
|
+
}
|
|
4007
|
+
return {
|
|
4008
|
+
phase: sent.phase,
|
|
4009
|
+
outcome: parseOutcome(raw.outcome)
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
__name(parseActionReport, "parseActionReport");
|
|
4013
|
+
var INVOCATION_KEYS = [
|
|
4014
|
+
"protocol",
|
|
4015
|
+
"action",
|
|
4016
|
+
"phase",
|
|
4017
|
+
"mode",
|
|
4018
|
+
"execution",
|
|
4019
|
+
"targets",
|
|
4020
|
+
"decisions",
|
|
4021
|
+
"restorePoint",
|
|
4022
|
+
"priorResult",
|
|
4023
|
+
"credentials",
|
|
4024
|
+
"limits"
|
|
4025
|
+
];
|
|
4026
|
+
var EVENT_LEVELS = {
|
|
4027
|
+
info: true,
|
|
4028
|
+
warn: true,
|
|
4029
|
+
error: true,
|
|
4030
|
+
success: true
|
|
4031
|
+
};
|
|
4032
|
+
var OUTCOME_STATUSES = {
|
|
4033
|
+
succeeded: true,
|
|
4034
|
+
failed: true,
|
|
4035
|
+
cancelled: true
|
|
4036
|
+
};
|
|
4037
|
+
function parseOutcome(value) {
|
|
4038
|
+
if (value === void 0) {
|
|
4039
|
+
throw new ActionProtocolError("A run or rollback report must carry an outcome.");
|
|
4040
|
+
}
|
|
4041
|
+
const raw = objectOf(value, "An outcome");
|
|
4042
|
+
onlyKeys(raw, [
|
|
4043
|
+
"status",
|
|
4044
|
+
"message",
|
|
4045
|
+
"data"
|
|
4046
|
+
], "An outcome");
|
|
4047
|
+
if (typeof raw.status !== "string" || !Object.hasOwn(OUTCOME_STATUSES, raw.status)) {
|
|
4048
|
+
throw new ActionProtocolError(`An outcome status of "${String(raw.status)}" is not in the vocabulary.`);
|
|
4049
|
+
}
|
|
4050
|
+
const status = raw.status;
|
|
4051
|
+
const message = nonEmpty(raw.message, "An outcome's message");
|
|
4052
|
+
if (raw.data === void 0) return {
|
|
4053
|
+
status,
|
|
4054
|
+
message
|
|
4055
|
+
};
|
|
4056
|
+
return {
|
|
4057
|
+
status,
|
|
4058
|
+
message,
|
|
4059
|
+
data: jsonObject(raw.data, "An outcome's data")
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
__name(parseOutcome, "parseOutcome");
|
|
4063
|
+
function parseLimits(value) {
|
|
4064
|
+
const raw = objectOf(value, "The invocation's limits");
|
|
4065
|
+
onlyKeys(raw, [
|
|
4066
|
+
"deadline",
|
|
4067
|
+
"maxEvents",
|
|
4068
|
+
"maxEventBytes",
|
|
4069
|
+
"maxReportBytes",
|
|
4070
|
+
"maxRestorePointBytes"
|
|
4071
|
+
], "The invocation's limits");
|
|
4072
|
+
return {
|
|
4073
|
+
deadline: isoInstant(raw.deadline, "The deadline"),
|
|
4074
|
+
maxEvents: positiveInteger(raw.maxEvents, "maxEvents"),
|
|
4075
|
+
maxEventBytes: positiveInteger(raw.maxEventBytes, "maxEventBytes"),
|
|
4076
|
+
maxReportBytes: positiveInteger(raw.maxReportBytes, "maxReportBytes"),
|
|
4077
|
+
maxRestorePointBytes: positiveInteger(raw.maxRestorePointBytes, "maxRestorePointBytes")
|
|
4078
|
+
};
|
|
4079
|
+
}
|
|
4080
|
+
__name(parseLimits, "parseLimits");
|
|
4081
|
+
function parseDecisions(value) {
|
|
4082
|
+
const raw = objectOf(value, "The invocation's decisions");
|
|
4083
|
+
if (raw.phase === "plan") {
|
|
4084
|
+
onlyKeys(raw, [
|
|
4085
|
+
"phase"
|
|
4086
|
+
], "A plan's decisions");
|
|
4087
|
+
return {
|
|
4088
|
+
phase: "plan"
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
if (raw.phase !== "run") {
|
|
4092
|
+
throw new ActionProtocolError(`A decisions phase of "${String(raw.phase)}" is not "plan" or "run".`);
|
|
4093
|
+
}
|
|
4094
|
+
onlyKeys(raw, [
|
|
4095
|
+
"phase",
|
|
4096
|
+
"recorded"
|
|
4097
|
+
], "A run's decisions");
|
|
4098
|
+
if (!Array.isArray(raw.recorded)) {
|
|
4099
|
+
throw new ActionProtocolError("A run's decisions must carry the recorded list, even when it is empty.");
|
|
4100
|
+
}
|
|
4101
|
+
const recorded = raw.recorded.map((entry) => {
|
|
4102
|
+
const decision = objectOf(entry, "A recorded decision");
|
|
4103
|
+
onlyKeys(decision, [
|
|
4104
|
+
"code",
|
|
4105
|
+
"acknowledgedBy",
|
|
4106
|
+
"acknowledgedAt"
|
|
4107
|
+
], "A recorded decision");
|
|
4108
|
+
if (!(0, validation_1.isDecisionCode)(decision.code)) {
|
|
4109
|
+
throw new ActionProtocolError(`A recorded decision of "${String(decision.code)}" is not in the vocabulary.`);
|
|
4110
|
+
}
|
|
4111
|
+
return {
|
|
4112
|
+
code: decision.code,
|
|
4113
|
+
acknowledgedBy: nonEmpty(decision.acknowledgedBy, "Who acknowledged a decision"),
|
|
4114
|
+
acknowledgedAt: isoInstant(decision.acknowledgedAt, "When a decision was acknowledged")
|
|
4115
|
+
};
|
|
4116
|
+
});
|
|
4117
|
+
if (new Set(recorded.map((decision) => decision.code)).size !== recorded.length) {
|
|
4118
|
+
throw new ActionProtocolError("A run's decisions record one code twice.");
|
|
4119
|
+
}
|
|
4120
|
+
return {
|
|
4121
|
+
phase: "run",
|
|
4122
|
+
recorded
|
|
4123
|
+
};
|
|
4124
|
+
}
|
|
4125
|
+
__name(parseDecisions, "parseDecisions");
|
|
4126
|
+
function parseTargets(value) {
|
|
4127
|
+
if (!Array.isArray(value)) {
|
|
4128
|
+
throw new ActionProtocolError("The invocation's targets must be an array.");
|
|
4129
|
+
}
|
|
4130
|
+
const targets = value.map((entry) => {
|
|
4131
|
+
const raw = objectOf(entry, "A target");
|
|
4132
|
+
onlyKeys(raw, [
|
|
4133
|
+
"ref",
|
|
4134
|
+
"parameters"
|
|
4135
|
+
], "A target");
|
|
4136
|
+
return {
|
|
4137
|
+
ref: nonEmpty(raw.ref, "A target's ref"),
|
|
4138
|
+
parameters: jsonObject(raw.parameters, "A target's parameters")
|
|
4139
|
+
};
|
|
4140
|
+
});
|
|
4141
|
+
if (new Set(targets.map((target) => target.ref)).size !== targets.length) {
|
|
4142
|
+
throw new ActionProtocolError("The invocation names one target twice.");
|
|
4143
|
+
}
|
|
4144
|
+
return targets;
|
|
4145
|
+
}
|
|
4146
|
+
__name(parseTargets, "parseTargets");
|
|
4147
|
+
function assertTargetCount(count, max, what) {
|
|
4148
|
+
if (count < 1 || count > max) {
|
|
4149
|
+
throw new ActionProtocolError(max === 1 ? `${what} acts on exactly one target; this invocation names ${count}.` : `${what} checks between 1 and ${max} targets; this invocation names ${count}.`);
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
__name(assertTargetCount, "assertTargetCount");
|
|
4153
|
+
function parseTokens(credentials) {
|
|
4154
|
+
onlyKeys(credentials, [
|
|
4155
|
+
"tokens"
|
|
4156
|
+
], "The invocation's credentials");
|
|
4157
|
+
if (!Array.isArray(credentials.tokens)) {
|
|
4158
|
+
throw new ActionProtocolError("The invocation's credentials must carry a tokens array, even when it is empty.");
|
|
4159
|
+
}
|
|
4160
|
+
const tokens2 = credentials.tokens.map((entry) => {
|
|
4161
|
+
const raw = objectOf(entry, "A token");
|
|
4162
|
+
onlyKeys(raw, [
|
|
4163
|
+
"audience",
|
|
4164
|
+
"token",
|
|
4165
|
+
"expiresOn"
|
|
4166
|
+
], "A token");
|
|
4167
|
+
const refusal = actionAudienceRefusal(raw.audience);
|
|
4168
|
+
if (refusal !== null) throw new ActionProtocolError(refusal);
|
|
4169
|
+
return {
|
|
4170
|
+
audience: raw.audience,
|
|
4171
|
+
token: nonEmpty(raw.token, "A token's value"),
|
|
4172
|
+
expiresOn: isoInstant(raw.expiresOn, "A token's expiry")
|
|
4173
|
+
};
|
|
4174
|
+
});
|
|
4175
|
+
if (new Set(tokens2.map((token2) => token2.audience)).size !== tokens2.length) {
|
|
4176
|
+
throw new ActionProtocolError("The invocation carries two tokens for one audience.");
|
|
4177
|
+
}
|
|
4178
|
+
return tokens2;
|
|
4179
|
+
}
|
|
4180
|
+
__name(parseTokens, "parseTokens");
|
|
4181
|
+
var DIGEST_PINNED_IMAGE = /^[a-z0-9][a-z0-9._\-/:]*@sha256:[0-9a-f]{64}$/;
|
|
4182
|
+
function digestPinned(value) {
|
|
4183
|
+
if (typeof value !== "string" || !DIGEST_PINNED_IMAGE.test(value)) {
|
|
4184
|
+
throw new ActionProtocolError(`The action's image "${String(value)}" is not addressed by digest. Nothing on the execution path resolves a tag (docs/128 \xA713.2).`);
|
|
4185
|
+
}
|
|
4186
|
+
return value;
|
|
4187
|
+
}
|
|
4188
|
+
__name(digestPinned, "digestPinned");
|
|
4189
|
+
function objectOf(value, what) {
|
|
4190
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
4191
|
+
throw new ActionProtocolError(`${what} must be an object.`);
|
|
4192
|
+
}
|
|
4193
|
+
return value;
|
|
4194
|
+
}
|
|
4195
|
+
__name(objectOf, "objectOf");
|
|
4196
|
+
function onlyKeys(raw, allowed, what) {
|
|
4197
|
+
for (const key of Object.keys(raw)) {
|
|
4198
|
+
if (!allowed.includes(key)) {
|
|
4199
|
+
throw new ActionProtocolError(`${what} carries "${key}", which this contract does not have.`);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
__name(onlyKeys, "onlyKeys");
|
|
4204
|
+
function nonEmpty(value, what) {
|
|
4205
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
4206
|
+
throw new ActionProtocolError(`${what} must be a non-empty string.`);
|
|
4207
|
+
}
|
|
4208
|
+
return value;
|
|
4209
|
+
}
|
|
4210
|
+
__name(nonEmpty, "nonEmpty");
|
|
4211
|
+
function positiveInteger(value, what) {
|
|
4212
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
|
|
4213
|
+
throw new ActionProtocolError(`The limit "${what}" must be a positive integer.`);
|
|
4214
|
+
}
|
|
4215
|
+
return value;
|
|
4216
|
+
}
|
|
4217
|
+
__name(positiveInteger, "positiveInteger");
|
|
4218
|
+
function isoInstant(value, what) {
|
|
4219
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
4220
|
+
throw new ActionProtocolError(`${what} must be an ISO-8601 instant.`);
|
|
4221
|
+
}
|
|
4222
|
+
return value;
|
|
4223
|
+
}
|
|
4224
|
+
__name(isoInstant, "isoInstant");
|
|
4225
|
+
function nullableObject(value, what) {
|
|
4226
|
+
return value === null ? null : jsonObject(value, what);
|
|
4227
|
+
}
|
|
4228
|
+
__name(nullableObject, "nullableObject");
|
|
4229
|
+
function jsonObject(value, what) {
|
|
4230
|
+
if (!isJsonObject(value)) {
|
|
4231
|
+
throw new ActionProtocolError(`${what} must be a JSON object.`);
|
|
4232
|
+
}
|
|
4233
|
+
return value;
|
|
4234
|
+
}
|
|
4235
|
+
__name(jsonObject, "jsonObject");
|
|
4236
|
+
function isJsonObject(value) {
|
|
4237
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
4238
|
+
const prototype = Object.getPrototypeOf(value);
|
|
4239
|
+
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
4240
|
+
return Object.values(value).every(isJsonValue);
|
|
4241
|
+
}
|
|
4242
|
+
__name(isJsonObject, "isJsonObject");
|
|
4243
|
+
function isJsonValue(value) {
|
|
4244
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
4245
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
4246
|
+
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
4247
|
+
return isJsonObject(value);
|
|
4248
|
+
}
|
|
4249
|
+
__name(isJsonValue, "isJsonValue");
|
|
4250
|
+
}
|
|
4251
|
+
});
|
|
4252
|
+
|
|
4253
|
+
// ../contracts/dist/action-signing.js
|
|
4254
|
+
var require_action_signing = __commonJS({
|
|
4255
|
+
"../contracts/dist/action-signing.js"(exports) {
|
|
4256
|
+
"use strict";
|
|
4257
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4258
|
+
value: true
|
|
4259
|
+
});
|
|
4260
|
+
exports.ACTION_SIGNATURE_REPOSITORY = exports.IMAGE_REVISION_LABEL = exports.IMAGE_SOURCE_LABEL = exports.COSIGN_SIGN_PREDICATE_TYPE = exports.IN_TOTO_STATEMENT_TYPE = exports.DSSE_IN_TOTO_PAYLOAD_TYPE = exports.SIGSTORE_BUNDLE_MEDIA_TYPE = void 0;
|
|
4261
|
+
exports.SIGSTORE_BUNDLE_MEDIA_TYPE = "application/vnd.dev.sigstore.bundle.v0.3+json";
|
|
4262
|
+
exports.DSSE_IN_TOTO_PAYLOAD_TYPE = "application/vnd.in-toto+json";
|
|
4263
|
+
exports.IN_TOTO_STATEMENT_TYPE = "https://in-toto.io/Statement/v1";
|
|
4264
|
+
exports.COSIGN_SIGN_PREDICATE_TYPE = "https://sigstore.dev/cosign/sign/v1";
|
|
4265
|
+
exports.IMAGE_SOURCE_LABEL = "org.opencontainers.image.source";
|
|
4266
|
+
exports.IMAGE_REVISION_LABEL = "org.opencontainers.image.revision";
|
|
4267
|
+
exports.ACTION_SIGNATURE_REPOSITORY = "ghcr.io/runveric/action-signatures";
|
|
4268
|
+
}
|
|
4269
|
+
});
|
|
4270
|
+
|
|
4271
|
+
// ../contracts/dist/oci-media-types.js
|
|
4272
|
+
var require_oci_media_types = __commonJS({
|
|
4273
|
+
"../contracts/dist/oci-media-types.js"(exports) {
|
|
4274
|
+
"use strict";
|
|
4275
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4276
|
+
value: true
|
|
4277
|
+
});
|
|
4278
|
+
exports.IMAGE_MANIFEST_MEDIA_TYPES = exports.MANIFEST_MEDIA_TYPES = exports.DOCKER_MANIFEST_LIST = exports.OCI_IMAGE_INDEX = exports.DOCKER_IMAGE_MANIFEST = exports.OCI_IMAGE_MANIFEST = void 0;
|
|
4279
|
+
exports.OCI_IMAGE_MANIFEST = "application/vnd.oci.image.manifest.v1+json";
|
|
4280
|
+
exports.DOCKER_IMAGE_MANIFEST = "application/vnd.docker.distribution.manifest.v2+json";
|
|
4281
|
+
exports.OCI_IMAGE_INDEX = "application/vnd.oci.image.index.v1+json";
|
|
4282
|
+
exports.DOCKER_MANIFEST_LIST = "application/vnd.docker.distribution.manifest.list.v2+json";
|
|
4283
|
+
exports.MANIFEST_MEDIA_TYPES = [
|
|
4284
|
+
exports.OCI_IMAGE_MANIFEST,
|
|
4285
|
+
exports.DOCKER_IMAGE_MANIFEST,
|
|
4286
|
+
exports.OCI_IMAGE_INDEX,
|
|
4287
|
+
exports.DOCKER_MANIFEST_LIST
|
|
4288
|
+
];
|
|
4289
|
+
exports.IMAGE_MANIFEST_MEDIA_TYPES = [
|
|
4290
|
+
exports.OCI_IMAGE_MANIFEST,
|
|
4291
|
+
exports.DOCKER_IMAGE_MANIFEST
|
|
4292
|
+
];
|
|
4293
|
+
}
|
|
4294
|
+
});
|
|
4295
|
+
|
|
4296
|
+
// ../contracts/dist/action-image.js
|
|
4297
|
+
var require_action_image = __commonJS({
|
|
4298
|
+
"../contracts/dist/action-image.js"(exports) {
|
|
4299
|
+
"use strict";
|
|
4300
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4301
|
+
value: true
|
|
4302
|
+
});
|
|
4303
|
+
exports.MAX_IMAGE_MANIFEST_BYTES = exports.ACTION_RUNTIME_IMAGE = exports.ACTION_RUNTIME_REPOSITORY = void 0;
|
|
4304
|
+
exports.imageConfigDescriptor = imageConfigDescriptor2;
|
|
4305
|
+
exports.actionImageRefusal = actionImageRefusal2;
|
|
4306
|
+
var action_repository_1 = require_action_repository();
|
|
4307
|
+
var action_signing_1 = require_action_signing();
|
|
4308
|
+
var oci_media_types_1 = require_oci_media_types();
|
|
4309
|
+
exports.ACTION_RUNTIME_REPOSITORY = "ghcr.io/runveric/action-runtime";
|
|
4310
|
+
exports.ACTION_RUNTIME_IMAGE = `${exports.ACTION_RUNTIME_REPOSITORY}@sha256:55126390dc54a79668e8475757f6de6dabc8c052242079d48d888eca4fdd5963`;
|
|
4311
|
+
exports.MAX_IMAGE_MANIFEST_BYTES = 64 * 1024;
|
|
4312
|
+
var isRecord = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isRecord");
|
|
4313
|
+
function imageConfigDescriptor2(manifest) {
|
|
4314
|
+
if (!isRecord(manifest) || typeof manifest.mediaType !== "string") return null;
|
|
4315
|
+
if (!oci_media_types_1.IMAGE_MANIFEST_MEDIA_TYPES.includes(manifest.mediaType) || manifest.schemaVersion !== 2) return null;
|
|
4316
|
+
const config = manifest.config;
|
|
4317
|
+
if (!isRecord(config) || typeof config.digest !== "string") return null;
|
|
4318
|
+
if (typeof config.size !== "number" || !Number.isInteger(config.size) || config.size < 0) return null;
|
|
4319
|
+
return {
|
|
4320
|
+
digest: config.digest,
|
|
4321
|
+
size: config.size
|
|
4322
|
+
};
|
|
4323
|
+
}
|
|
4324
|
+
__name(imageConfigDescriptor2, "imageConfigDescriptor");
|
|
4325
|
+
function actionImageRefusal2(input) {
|
|
4326
|
+
const { key, image, manifest, config, provenance: provenance2 } = input;
|
|
4327
|
+
const mediaType = isRecord(manifest) ? manifest.mediaType : void 0;
|
|
4328
|
+
if (typeof mediaType !== "string" || !oci_media_types_1.IMAGE_MANIFEST_MEDIA_TYPES.includes(mediaType)) {
|
|
4329
|
+
return `${image} is ${typeof mediaType === "string" ? `a ${mediaType}` : "a manifest of no declared type"}, not one image. An engine action's digest names exactly one linux/amd64 image manifest \u2014 never an index of several.`;
|
|
4330
|
+
}
|
|
4331
|
+
if (imageConfigDescriptor2(manifest) === null) {
|
|
4332
|
+
return `${image} is not an image manifest \u2014 it names no config descriptor (schemaVersion 2, a digest and a size).`;
|
|
4333
|
+
}
|
|
4334
|
+
if (!isRecord(config)) {
|
|
4335
|
+
return `${image}'s config is not a JSON object, so it cannot say what it was built for.`;
|
|
4336
|
+
}
|
|
4337
|
+
const platform = `${String(config.os)}/${String(config.architecture)}`;
|
|
4338
|
+
if (platform !== "linux/amd64") {
|
|
4339
|
+
return `${image} is built for ${platform}; an engine action runs on linux/amd64, which is what Container Apps Jobs run.`;
|
|
4340
|
+
}
|
|
4341
|
+
const labels = isRecord(config.config) && isRecord(config.config.Labels) ? config.config.Labels : {};
|
|
4342
|
+
const expected = (0, action_repository_1.actionSourceRepository)(key);
|
|
4343
|
+
const source = labels[action_signing_1.IMAGE_SOURCE_LABEL];
|
|
4344
|
+
if (source !== expected) {
|
|
4345
|
+
return `the image of action "${key}" says it was built in ${source === void 0 ? "no repository (it carries no " + action_signing_1.IMAGE_SOURCE_LABEL + " label)" : JSON.stringify(source)}, not ${expected}. A signature binds a digest and never a name, so an image built for another action cannot run under this one's manifest.`;
|
|
4346
|
+
}
|
|
4347
|
+
if (provenance2.repository !== expected) {
|
|
4348
|
+
return `the artifact of action "${key}" says it was authored in ${JSON.stringify(provenance2.repository)}, not ${expected}, which its image names.`;
|
|
4349
|
+
}
|
|
4350
|
+
const revision = labels[action_signing_1.IMAGE_REVISION_LABEL];
|
|
4351
|
+
if (revision !== provenance2.commit) {
|
|
4352
|
+
return `the image of action "${key}" says it was built at ${revision === void 0 ? "no commit (it carries no " + action_signing_1.IMAGE_REVISION_LABEL + " label)" : JSON.stringify(revision)}, not ${provenance2.commit}, the commit its artifact was published from. An image and the manifest it runs under come from one commit, so neither can be swapped for another's.`;
|
|
4353
|
+
}
|
|
4354
|
+
return null;
|
|
4355
|
+
}
|
|
4356
|
+
__name(actionImageRefusal2, "actionImageRefusal");
|
|
4357
|
+
}
|
|
4358
|
+
});
|
|
4359
|
+
|
|
3218
4360
|
// ../contracts/dist/runner-pool-presence.js
|
|
3219
4361
|
var require_runner_pool_presence = __commonJS({
|
|
3220
4362
|
"../contracts/dist/runner-pool-presence.js"(exports) {
|
|
@@ -4190,6 +5332,11 @@ var require_dist = __commonJS({
|
|
|
4190
5332
|
__exportStar(require_runner_install(), exports);
|
|
4191
5333
|
__exportStar(require_authoring_cli(), exports);
|
|
4192
5334
|
__exportStar(require_runners(), exports);
|
|
5335
|
+
__exportStar(require_scoped_credential(), exports);
|
|
5336
|
+
__exportStar(require_action_protocol(), exports);
|
|
5337
|
+
__exportStar(require_action_signing(), exports);
|
|
5338
|
+
__exportStar(require_oci_media_types(), exports);
|
|
5339
|
+
__exportStar(require_action_image(), exports);
|
|
4193
5340
|
__exportStar(require_runner_pool_presence(), exports);
|
|
4194
5341
|
__exportStar(require_routable_target(), exports);
|
|
4195
5342
|
__exportStar(require_runner_pool_routing(), exports);
|
|
@@ -4427,6 +5574,7 @@ var require_manifest_validator = __commonJS({
|
|
|
4427
5574
|
exports.canonicalJson = canonicalJson;
|
|
4428
5575
|
exports.sha256Hex = sha256Hex;
|
|
4429
5576
|
exports.isSafeRelativePath = isSafeRelativePath;
|
|
5577
|
+
exports.isEgressDestination = isEgressDestination;
|
|
4430
5578
|
var node_crypto_1 = __require("crypto");
|
|
4431
5579
|
var node_net_1 = __require("net");
|
|
4432
5580
|
var contracts_1 = require_dist();
|
|
@@ -5838,7 +6986,7 @@ var require_parameters_location = __commonJS({
|
|
|
5838
6986
|
});
|
|
5839
6987
|
exports.resolveParametersFile = resolveParametersFile;
|
|
5840
6988
|
exports.resolveParametersFileOf = resolveParametersFileOf;
|
|
5841
|
-
exports.readManifest =
|
|
6989
|
+
exports.readManifest = readManifest2;
|
|
5842
6990
|
var yaml_1 = __require("yaml");
|
|
5843
6991
|
var manifest_validator_1 = require_manifest_validator();
|
|
5844
6992
|
var package_validation_1 = require_package_validation();
|
|
@@ -5849,7 +6997,7 @@ var require_parameters_location = __commonJS({
|
|
|
5849
6997
|
reason: "manifest_missing"
|
|
5850
6998
|
};
|
|
5851
6999
|
}
|
|
5852
|
-
const manifest =
|
|
7000
|
+
const manifest = readManifest2(manifestSource);
|
|
5853
7001
|
if (!manifest) return {
|
|
5854
7002
|
resolved: false,
|
|
5855
7003
|
reason: "manifest_unparseable"
|
|
@@ -5877,7 +7025,7 @@ var require_parameters_location = __commonJS({
|
|
|
5877
7025
|
return resolveParametersFile(files.get(package_validation_1.MANIFEST_FILE));
|
|
5878
7026
|
}
|
|
5879
7027
|
__name(resolveParametersFileOf, "resolveParametersFileOf");
|
|
5880
|
-
function
|
|
7028
|
+
function readManifest2(source) {
|
|
5881
7029
|
try {
|
|
5882
7030
|
const document = (0, yaml_1.parseDocument)(source);
|
|
5883
7031
|
if (document.errors.length > 0) return void 0;
|
|
@@ -5887,7 +7035,7 @@ var require_parameters_location = __commonJS({
|
|
|
5887
7035
|
return void 0;
|
|
5888
7036
|
}
|
|
5889
7037
|
}
|
|
5890
|
-
__name(
|
|
7038
|
+
__name(readManifest2, "readManifest");
|
|
5891
7039
|
}
|
|
5892
7040
|
});
|
|
5893
7041
|
|
|
@@ -7219,7 +8367,8 @@ var require_dist2 = __commonJS({
|
|
|
7219
8367
|
Object.defineProperty(exports, "__esModule", {
|
|
7220
8368
|
value: true
|
|
7221
8369
|
});
|
|
7222
|
-
exports.
|
|
8370
|
+
exports.reservedImportPaths = exports.generateImportedPackage = exports.authoredEntrypointOf = exports.authoredBodyPath = exports.powerShellDetection = exports.parseProbeOutput = exports.mapDeclaredParameters = exports.POWERSHELL_PARAM_PROBE = exports.pathSegments = exports.offsetToLocation = exports.locate = exports.interpreterForPath = exports.interpreterEntryFileList = exports.PACKAGE_INTERPRETER_EXTENSIONS = exports.PACKAGE_INTERPRETER_LAUNCH = exports.lintActionPackage = exports.sortFindings = exports.mergeFindings = exports.findingFromValidation = exports.resolveParametersFileOf = exports.resolveParametersFile = exports.readManifest = exports.checkActionPackage = exports.validateActionPackage = exports.REQUIRED_PACKAGE_FILES = exports.MANIFEST_FILE = exports.validatePackageResult = exports.PackageProtocolError = exports.normalizePackageRuntime = exports.checkOciImageReference = exports.PackageRuntimeDeclarationError = exports.PARAMETER_CONTROLS = exports.PARAMETER_PROPERTY_FIELDS = exports.PARAMETER_SCHEMA_FIELDS = exports.CREDENTIAL_SCOPE_PATTERN = exports.SPDX_ID_PATTERN = exports.DURATION_PATTERN = exports.SEMVER_PATTERN = exports.PACKAGE_ID_PATTERN = exports.MANIFEST_FIELDS = exports.RISK_LEVELS = exports.PROVIDERS = exports.ACTION_CATEGORIES = exports.isEgressDestination = exports.isSafeRelativePath = exports.sha256Hex = exports.canonicalJson = exports.validateParameterSchema = exports.validateManifest = exports.parseAndValidateManifest = void 0;
|
|
8371
|
+
exports.scaffoldActionPackage = void 0;
|
|
7223
8372
|
var manifest_validator_1 = require_manifest_validator();
|
|
7224
8373
|
Object.defineProperty(exports, "parseAndValidateManifest", {
|
|
7225
8374
|
enumerable: true,
|
|
@@ -7257,6 +8406,12 @@ var require_dist2 = __commonJS({
|
|
|
7257
8406
|
return manifest_validator_1.isSafeRelativePath;
|
|
7258
8407
|
}, "get")
|
|
7259
8408
|
});
|
|
8409
|
+
Object.defineProperty(exports, "isEgressDestination", {
|
|
8410
|
+
enumerable: true,
|
|
8411
|
+
get: /* @__PURE__ */ __name(function() {
|
|
8412
|
+
return manifest_validator_1.isEgressDestination;
|
|
8413
|
+
}, "get")
|
|
8414
|
+
});
|
|
7260
8415
|
var manifest_schema_1 = require_manifest_schema();
|
|
7261
8416
|
Object.defineProperty(exports, "ACTION_CATEGORIES", {
|
|
7262
8417
|
enumerable: true,
|
|
@@ -7537,7 +8692,7 @@ var require_dist2 = __commonJS({
|
|
|
7537
8692
|
});
|
|
7538
8693
|
|
|
7539
8694
|
// package.json
|
|
7540
|
-
var version = "0.
|
|
8695
|
+
var version = "0.4.0";
|
|
7541
8696
|
|
|
7542
8697
|
// src/report.ts
|
|
7543
8698
|
var useColour = process.stdout.isTTY === true && !process.env.NO_COLOR;
|
|
@@ -7647,7 +8802,7 @@ function printResult(result) {
|
|
|
7647
8802
|
__name(printResult, "printResult");
|
|
7648
8803
|
|
|
7649
8804
|
// src/catalog/publish-action.ts
|
|
7650
|
-
var
|
|
8805
|
+
var import_contracts3 = __toESM(require_dist());
|
|
7651
8806
|
import { readFileSync } from "fs";
|
|
7652
8807
|
import { dirname, resolve } from "path";
|
|
7653
8808
|
import { parse as parseYaml } from "yaml";
|
|
@@ -7686,7 +8841,7 @@ var EMPTY_CONFIG_DESCRIPTOR = {
|
|
|
7686
8841
|
digest: sha256(EMPTY_CONFIG),
|
|
7687
8842
|
size: EMPTY_CONFIG.length
|
|
7688
8843
|
};
|
|
7689
|
-
var
|
|
8844
|
+
var MANIFEST_ACCEPT = import_contracts.MANIFEST_MEDIA_TYPES.join(", ");
|
|
7690
8845
|
function provenance(flags, dir) {
|
|
7691
8846
|
const git = /* @__PURE__ */ __name((...args) => {
|
|
7692
8847
|
try {
|
|
@@ -7724,7 +8879,7 @@ function buildArtifact(document) {
|
|
|
7724
8879
|
`);
|
|
7725
8880
|
const manifest = {
|
|
7726
8881
|
schemaVersion: 2,
|
|
7727
|
-
mediaType:
|
|
8882
|
+
mediaType: import_contracts.OCI_IMAGE_MANIFEST,
|
|
7728
8883
|
artifactType: import_contracts.CATALOG_ARTIFACT_MEDIA_TYPE,
|
|
7729
8884
|
config: EMPTY_CONFIG_DESCRIPTOR,
|
|
7730
8885
|
layers: [
|
|
@@ -7764,14 +8919,14 @@ function basicCredential() {
|
|
|
7764
8919
|
}
|
|
7765
8920
|
__name(basicCredential, "basicCredential");
|
|
7766
8921
|
var tokens = /* @__PURE__ */ new Map();
|
|
7767
|
-
async function token(repository, challenge) {
|
|
8922
|
+
async function token(repository, challenge, access) {
|
|
7768
8923
|
const field = /* @__PURE__ */ __name((name) => new RegExp(`${name}="([^"]*)"`).exec(challenge ?? "")?.[1], "field");
|
|
7769
8924
|
const realm = field("realm");
|
|
7770
8925
|
if (!realm) throw new Error(`${repository.host} asked for credentials without a Bearer challenge.`);
|
|
7771
8926
|
const url = new URL(realm);
|
|
7772
8927
|
const service = field("service");
|
|
7773
8928
|
if (service) url.searchParams.set("service", service);
|
|
7774
|
-
url.searchParams.set("scope", `repository:${repository.path}
|
|
8929
|
+
url.searchParams.set("scope", `repository:${repository.path}:${access}`);
|
|
7775
8930
|
const credential = basicCredential();
|
|
7776
8931
|
const answer = await fetch(url, {
|
|
7777
8932
|
headers: credential ? {
|
|
@@ -7779,15 +8934,15 @@ async function token(repository, challenge) {
|
|
|
7779
8934
|
} : {}
|
|
7780
8935
|
});
|
|
7781
8936
|
if (!answer.ok) {
|
|
7782
|
-
throw new Error(`${repository.host} refused a push token for ${repository.path}: HTTP ${answer.status}` + (credential ? "." : " \u2014 set GHCR_TOKEN to a token with write:packages, or in a workflow GITHUB_TOKEN with packages: write."));
|
|
8937
|
+
throw new Error(`${repository.host} refused a ${access === "pull" ? "pull" : "push"} token for ${repository.path}: HTTP ${answer.status}` + (credential || access === "pull" ? "." : " \u2014 set GHCR_TOKEN to a token with write:packages, or in a workflow GITHUB_TOKEN with packages: write."));
|
|
7783
8938
|
}
|
|
7784
8939
|
const body = await answer.json();
|
|
7785
8940
|
const value = body.token ?? body.access_token ?? "";
|
|
7786
|
-
tokens.set(repository.path
|
|
8941
|
+
tokens.set(`${repository.path} ${access}`, value);
|
|
7787
8942
|
return value;
|
|
7788
8943
|
}
|
|
7789
8944
|
__name(token, "token");
|
|
7790
|
-
async function call(repository, method, path, { headers = {}, body } = {}) {
|
|
8945
|
+
async function call(repository, method, path, { headers = {}, body, access = "pull,push" } = {}) {
|
|
7791
8946
|
const url = path.startsWith("http") ? path : `${origin(repository.host)}/v2/${repository.path}/${path}`;
|
|
7792
8947
|
const send = /* @__PURE__ */ __name((bearer) => fetch(url, {
|
|
7793
8948
|
method,
|
|
@@ -7800,8 +8955,8 @@ async function call(repository, method, path, { headers = {}, body } = {}) {
|
|
|
7800
8955
|
} : {}
|
|
7801
8956
|
}
|
|
7802
8957
|
}), "send");
|
|
7803
|
-
let answer = await send(tokens.get(repository.path));
|
|
7804
|
-
if (answer.status === 401) answer = await send(await token(repository, answer.headers.get("www-authenticate")));
|
|
8958
|
+
let answer = await send(tokens.get(`${repository.path} ${access}`));
|
|
8959
|
+
if (answer.status === 401) answer = await send(await token(repository, answer.headers.get("www-authenticate"), access));
|
|
7805
8960
|
return answer;
|
|
7806
8961
|
}
|
|
7807
8962
|
__name(call, "call");
|
|
@@ -7826,12 +8981,54 @@ __name(pushBlob, "pushBlob");
|
|
|
7826
8981
|
async function manifestExists(repository, digest) {
|
|
7827
8982
|
const answer = await call(repository, "HEAD", `manifests/${digest}`, {
|
|
7828
8983
|
headers: {
|
|
7829
|
-
Accept:
|
|
8984
|
+
Accept: import_contracts.OCI_IMAGE_MANIFEST
|
|
7830
8985
|
}
|
|
7831
8986
|
});
|
|
7832
8987
|
return answer.ok;
|
|
7833
8988
|
}
|
|
7834
8989
|
__name(manifestExists, "manifestExists");
|
|
8990
|
+
async function readVerified(repository, kind, digest, size = null) {
|
|
8991
|
+
if (!isDigest(digest)) throw new Error(`"${digest}" is not a digest, so ${repository.ref} cannot be asked for it.`);
|
|
8992
|
+
const answer = await call(repository, "GET", `${kind}/${digest}`, {
|
|
8993
|
+
access: "pull",
|
|
8994
|
+
headers: kind === "manifests" ? {
|
|
8995
|
+
Accept: MANIFEST_ACCEPT
|
|
8996
|
+
} : {}
|
|
8997
|
+
});
|
|
8998
|
+
if (!answer.ok) {
|
|
8999
|
+
throw new Error(`${repository.ref}@${digest} could not be read: HTTP ${answer.status}${answer.status === 404 ? " \u2014 it is not in the registry" : ""}.`);
|
|
9000
|
+
}
|
|
9001
|
+
const bytes = Buffer.from(await answer.arrayBuffer());
|
|
9002
|
+
const served = sha256(bytes);
|
|
9003
|
+
if (served !== digest || size !== null && bytes.length !== size) {
|
|
9004
|
+
throw new Error(`${repository.host} served ${bytes.length} bytes hashing to ${served} for ${repository.ref}@${digest}${size === null ? "" : ` (${size} bytes named)`}. Refused: a digest this command did not compute is not a pin.`);
|
|
9005
|
+
}
|
|
9006
|
+
return bytes;
|
|
9007
|
+
}
|
|
9008
|
+
__name(readVerified, "readVerified");
|
|
9009
|
+
var readManifest = /* @__PURE__ */ __name((repository, digest) => readVerified(repository, "manifests", digest), "readManifest");
|
|
9010
|
+
var readBlob = /* @__PURE__ */ __name((repository, digest, size) => readVerified(repository, "blobs", digest, size), "readBlob");
|
|
9011
|
+
function parseJsonBytes(bytes, what) {
|
|
9012
|
+
try {
|
|
9013
|
+
return JSON.parse(new TextDecoder("utf-8", {
|
|
9014
|
+
fatal: true
|
|
9015
|
+
}).decode(bytes));
|
|
9016
|
+
} catch (cause) {
|
|
9017
|
+
throw new Error(`${what} is not UTF-8 JSON. (${cause instanceof Error ? cause.message : String(cause)})`);
|
|
9018
|
+
}
|
|
9019
|
+
}
|
|
9020
|
+
__name(parseJsonBytes, "parseJsonBytes");
|
|
9021
|
+
async function readArtifactDocument(repository, digest) {
|
|
9022
|
+
const what = `${repository.ref}@${digest}`;
|
|
9023
|
+
const manifest = parseJsonBytes(await readManifest(repository, digest), `the manifest of ${what}`);
|
|
9024
|
+
const layers = Array.isArray(manifest?.layers) ? manifest.layers : [];
|
|
9025
|
+
const layer = layers[0];
|
|
9026
|
+
if (manifest?.mediaType !== import_contracts.OCI_IMAGE_MANIFEST || layers.length !== 1 || layer?.mediaType !== import_contracts.CATALOG_ARTIFACT_MEDIA_TYPE || typeof layer.digest !== "string" || typeof layer.size !== "number") {
|
|
9027
|
+
throw new Error(`${what} is not a catalog artifact: expected one OCI manifest with exactly one ${import_contracts.CATALOG_ARTIFACT_MEDIA_TYPE} layer.`);
|
|
9028
|
+
}
|
|
9029
|
+
return parseJsonBytes(await readBlob(repository, layer.digest, layer.size), `the document of ${what}`);
|
|
9030
|
+
}
|
|
9031
|
+
__name(readArtifactDocument, "readArtifactDocument");
|
|
7835
9032
|
async function pushArtifact(repository, artifact, tag) {
|
|
7836
9033
|
await pushBlob(repository, EMPTY_CONFIG);
|
|
7837
9034
|
await pushBlob(repository, artifact.documentBytes);
|
|
@@ -7841,7 +9038,7 @@ async function pushArtifact(repository, artifact, tag) {
|
|
|
7841
9038
|
]) {
|
|
7842
9039
|
const put = await call(repository, "PUT", `manifests/${reference}`, {
|
|
7843
9040
|
headers: {
|
|
7844
|
-
"Content-Type":
|
|
9041
|
+
"Content-Type": import_contracts.OCI_IMAGE_MANIFEST
|
|
7845
9042
|
},
|
|
7846
9043
|
body: artifact.manifestBytes
|
|
7847
9044
|
});
|
|
@@ -7851,7 +9048,7 @@ async function pushArtifact(repository, artifact, tag) {
|
|
|
7851
9048
|
}
|
|
7852
9049
|
const asked = await call(repository, "HEAD", `manifests/${tag}`, {
|
|
7853
9050
|
headers: {
|
|
7854
|
-
Accept:
|
|
9051
|
+
Accept: import_contracts.OCI_IMAGE_MANIFEST
|
|
7855
9052
|
}
|
|
7856
9053
|
});
|
|
7857
9054
|
const reported = asked.headers.get("docker-content-digest");
|
|
@@ -7868,7 +9065,7 @@ var defaultTag = /* @__PURE__ */ __name(() => (/* @__PURE__ */ new Date()).toISO
|
|
|
7868
9065
|
|
|
7869
9066
|
// src/catalog/flags.ts
|
|
7870
9067
|
function parseCatalogFlags(argv, known, repeated = []) {
|
|
7871
|
-
const
|
|
9068
|
+
const single2 = {};
|
|
7872
9069
|
const many = {};
|
|
7873
9070
|
for (let index = 0; index < argv.length; index += 1) {
|
|
7874
9071
|
const argument = argv[index];
|
|
@@ -7884,28 +9081,67 @@ function parseCatalogFlags(argv, known, repeated = []) {
|
|
|
7884
9081
|
}
|
|
7885
9082
|
if (value === void 0 || value === "" || value.startsWith("--")) throw new Error(`--${name} needs a value.`);
|
|
7886
9083
|
if (repeated.includes(name)) (many[name] ??= []).push(value);
|
|
7887
|
-
else
|
|
9084
|
+
else single2[name] = value;
|
|
7888
9085
|
}
|
|
7889
9086
|
return {
|
|
7890
|
-
single,
|
|
9087
|
+
single: single2,
|
|
7891
9088
|
many
|
|
7892
9089
|
};
|
|
7893
9090
|
}
|
|
7894
9091
|
__name(parseCatalogFlags, "parseCatalogFlags");
|
|
7895
9092
|
|
|
9093
|
+
// src/catalog/image.ts
|
|
9094
|
+
var import_contracts2 = __toESM(require_dist());
|
|
9095
|
+
function parseImageReference(value, origin2) {
|
|
9096
|
+
const at = value.lastIndexOf("@");
|
|
9097
|
+
const digest = at === -1 ? "" : value.slice(at + 1);
|
|
9098
|
+
if (at === -1 || !isDigest(digest)) {
|
|
9099
|
+
throw new Error(`${origin2} "${value}" is not <repository>@<digest>. An engine action's image is named by its digest \u2014 sha256: and 64 lowercase hex \u2014 never by a tag, which a registry can repoint.`);
|
|
9100
|
+
}
|
|
9101
|
+
const repository = parseRepository(value.slice(0, at), origin2);
|
|
9102
|
+
return {
|
|
9103
|
+
repository,
|
|
9104
|
+
digest,
|
|
9105
|
+
ref: `${repository.ref}@${digest}`
|
|
9106
|
+
};
|
|
9107
|
+
}
|
|
9108
|
+
__name(parseImageReference, "parseImageReference");
|
|
9109
|
+
async function imageRefusal(image, key, provenance2) {
|
|
9110
|
+
const manifestBytes = await readManifest(image.repository, image.digest);
|
|
9111
|
+
if (manifestBytes.length > import_contracts2.MAX_IMAGE_MANIFEST_BYTES) {
|
|
9112
|
+
return `the image manifest of ${image.ref} is ${manifestBytes.length} bytes; the limit is ${import_contracts2.MAX_IMAGE_MANIFEST_BYTES}.`;
|
|
9113
|
+
}
|
|
9114
|
+
const manifest = parseJsonBytes(manifestBytes, `the image manifest of ${image.ref}`);
|
|
9115
|
+
const descriptor = (0, import_contracts2.imageConfigDescriptor)(manifest);
|
|
9116
|
+
const config = descriptor === null ? null : parseJsonBytes(await readBlob(image.repository, descriptor.digest, descriptor.size), `the image config of ${image.ref}`);
|
|
9117
|
+
return (0, import_contracts2.actionImageRefusal)({
|
|
9118
|
+
key,
|
|
9119
|
+
image: image.ref,
|
|
9120
|
+
manifest,
|
|
9121
|
+
config,
|
|
9122
|
+
provenance: provenance2
|
|
9123
|
+
});
|
|
9124
|
+
}
|
|
9125
|
+
__name(imageRefusal, "imageRefusal");
|
|
9126
|
+
|
|
7896
9127
|
// src/catalog/publish-action.ts
|
|
7897
|
-
var PUBLISH_ACTION_USAGE = "runveric catalog publish-action --manifest <file.yaml> --to <registry>/<namespace>/<repository>\n [--tag <tag>]
|
|
9128
|
+
var PUBLISH_ACTION_USAGE = "runveric catalog publish-action --manifest <file.yaml> --to <registry>/<namespace>/<repository>\n [--image <repository>@<digest>] [--tag <tag>]\n [--repository <source url>] [--commit <sha>]";
|
|
7898
9129
|
var isMapping = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isMapping");
|
|
7899
9130
|
async function runPublishAction(argv) {
|
|
7900
9131
|
const { single: flags } = parseCatalogFlags(argv, [
|
|
7901
9132
|
"manifest",
|
|
7902
9133
|
"to",
|
|
9134
|
+
"image",
|
|
7903
9135
|
"tag",
|
|
7904
9136
|
"repository",
|
|
7905
9137
|
"commit"
|
|
7906
9138
|
]);
|
|
7907
9139
|
if (!flags.manifest || !flags.to) throw new Error("--manifest and --to are required.");
|
|
7908
9140
|
const repository = parseRepository(flags.to, "--to");
|
|
9141
|
+
const image = flags.image === void 0 ? null : parseImageReference(flags.image, "--image");
|
|
9142
|
+
if (image !== null && image.repository.ref !== repository.ref) {
|
|
9143
|
+
throw new Error(`--image ${image.ref} is outside the artifact's repository ${repository.ref}. An engine action's image lives in its own package, so its artifact names it by digest alone (docs/128 \xA717.2 D2) \u2014 push the image to ${repository.ref}.`);
|
|
9144
|
+
}
|
|
7909
9145
|
const path = resolve(flags.manifest);
|
|
7910
9146
|
const manifest = readFileSync(path, "utf8");
|
|
7911
9147
|
let parsed;
|
|
@@ -7917,8 +9153,15 @@ async function runPublishAction(argv) {
|
|
|
7917
9153
|
const fields = isMapping(parsed) ? parsed : {};
|
|
7918
9154
|
const key = typeof fields.key === "string" && fields.key.length > 0 ? fields.key : null;
|
|
7919
9155
|
if (key === null) throw new Error(`${flags.manifest} declares no top-level \`key:\` \u2014 is it a catalog manifest?`);
|
|
7920
|
-
const misnamed = (0,
|
|
9156
|
+
const misnamed = (0, import_contracts3.actionPackageRefusal)(key, repository.ref);
|
|
7921
9157
|
if (misnamed !== null) throw new Error(`--to: ${misnamed}`);
|
|
9158
|
+
const executes = isMapping(fields.execution);
|
|
9159
|
+
if (executes && image === null) {
|
|
9160
|
+
throw new Error(`${flags.manifest} declares execution, so it is an engine action: publish it with --image <repository>@<digest>, the image its workflow built. Without one the server refuses it at plan.`);
|
|
9161
|
+
}
|
|
9162
|
+
if (!executes && image !== null) {
|
|
9163
|
+
throw new Error(`${flags.manifest} declares no execution, so nothing would ever run --image ${image.ref}. A built-in action is published without one.`);
|
|
9164
|
+
}
|
|
7922
9165
|
let tag;
|
|
7923
9166
|
if (fields.declares === "definition+version") {
|
|
7924
9167
|
const version2 = typeof fields.version === "string" ? fields.version : null;
|
|
@@ -7931,13 +9174,25 @@ async function runPublishAction(argv) {
|
|
|
7931
9174
|
tag = flags.tag ?? defaultTag();
|
|
7932
9175
|
}
|
|
7933
9176
|
requireTag(tag, flags.tag !== void 0 ? "--tag" : `${flags.manifest}'s version`);
|
|
7934
|
-
const
|
|
7935
|
-
|
|
9177
|
+
const recorded = provenance(flags, dirname(path));
|
|
9178
|
+
if (image !== null) {
|
|
9179
|
+
const refusal = await imageRefusal(image, key, recorded);
|
|
9180
|
+
if (refusal !== null) throw new Error(`--image: ${refusal}`);
|
|
9181
|
+
}
|
|
9182
|
+
const artifact = buildArtifact(image === null ? {
|
|
9183
|
+
schemaVersion: import_contracts3.CATALOG_ACTION_ARTIFACT_SCHEMA_V1,
|
|
9184
|
+
manifest,
|
|
9185
|
+
provenance: recorded
|
|
9186
|
+
} : {
|
|
9187
|
+
schemaVersion: import_contracts3.CATALOG_ACTION_ARTIFACT_SCHEMA_V2,
|
|
7936
9188
|
manifest,
|
|
7937
|
-
provenance:
|
|
9189
|
+
provenance: recorded,
|
|
9190
|
+
image: {
|
|
9191
|
+
digest: image.digest
|
|
9192
|
+
}
|
|
7938
9193
|
});
|
|
7939
9194
|
const digest = await pushArtifact(repository, artifact, tag);
|
|
7940
|
-
process.stderr.write(`\u2713 ${key} published to ${repository.ref}:${tag}
|
|
9195
|
+
process.stderr.write(`\u2713 ${key} published to ${repository.ref}:${tag}${image === null ? "" : `, naming the image ${image.digest}`}
|
|
7941
9196
|
`);
|
|
7942
9197
|
process.stderr.write(` the registry reports ${digest} \u2014 the digest a release must name.
|
|
7943
9198
|
`);
|
|
@@ -7947,7 +9202,7 @@ async function runPublishAction(argv) {
|
|
|
7947
9202
|
__name(runPublishAction, "runPublishAction");
|
|
7948
9203
|
|
|
7949
9204
|
// src/catalog/publish-release.ts
|
|
7950
|
-
var
|
|
9205
|
+
var import_contracts4 = __toESM(require_dist());
|
|
7951
9206
|
import { readFileSync as readFileSync2 } from "fs";
|
|
7952
9207
|
import { parse as parseYaml2 } from "yaml";
|
|
7953
9208
|
var PUBLISH_RELEASE_USAGE = "runveric catalog publish-release (--from <release.yaml> | --action <key>=<repository>@<digest> \u2026)\n --to <registry>/<namespace>/<repository> [--version <label>]\n [--tag <tag>] [--repository <source url>] [--commit <sha>]";
|
|
@@ -7972,7 +9227,7 @@ function specFromFile(path) {
|
|
|
7972
9227
|
} catch (cause) {
|
|
7973
9228
|
throw new Error(`--from ${path} could not be read as YAML. (${cause instanceof Error ? cause.message : String(cause)})`);
|
|
7974
9229
|
}
|
|
7975
|
-
const spec = (0,
|
|
9230
|
+
const spec = (0, import_contracts4.parseCatalogReleaseSpec)(value);
|
|
7976
9231
|
return {
|
|
7977
9232
|
version: spec.version,
|
|
7978
9233
|
entries: spec.actions.map((action) => ({
|
|
@@ -8022,7 +9277,7 @@ async function runPublishRelease(argv) {
|
|
|
8022
9277
|
if (!isDigest(entry.digest)) {
|
|
8023
9278
|
throw new Error(`${entry.label}: "${entry.digest}" is not a digest. A release names artifacts by digest only.`);
|
|
8024
9279
|
}
|
|
8025
|
-
const misnamed = (0,
|
|
9280
|
+
const misnamed = (0, import_contracts4.actionPackageRefusal)(entry.key, entry.artifactRef);
|
|
8026
9281
|
if (misnamed !== null) throw new Error(`${entry.label}: ${misnamed}`);
|
|
8027
9282
|
return {
|
|
8028
9283
|
...entry,
|
|
@@ -8035,7 +9290,7 @@ async function runPublishRelease(argv) {
|
|
|
8035
9290
|
}
|
|
8036
9291
|
}
|
|
8037
9292
|
const artifact = buildArtifact({
|
|
8038
|
-
schemaVersion:
|
|
9293
|
+
schemaVersion: import_contracts4.CATALOG_RELEASE_SCHEMA_V1,
|
|
8039
9294
|
version: version2,
|
|
8040
9295
|
provenance: provenance(flags, process.cwd()),
|
|
8041
9296
|
actions: actions.map(({ key, artifactRef, digest: digest2 }) => ({
|
|
@@ -8054,20 +9309,124 @@ async function runPublishRelease(argv) {
|
|
|
8054
9309
|
}
|
|
8055
9310
|
__name(runPublishRelease, "runPublishRelease");
|
|
8056
9311
|
|
|
9312
|
+
// src/catalog/verify-image.ts
|
|
9313
|
+
var import_contracts5 = __toESM(require_dist());
|
|
9314
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
9315
|
+
import { parse as parseYaml3 } from "yaml";
|
|
9316
|
+
var VERIFY_IMAGE_USAGE = "runveric catalog verify-image (<repository>@<digest> --key <action key> --commit <sha> | --from <release.yaml>)";
|
|
9317
|
+
var COMMIT = /^[0-9a-f]{40}$/;
|
|
9318
|
+
var isMapping2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isMapping");
|
|
9319
|
+
function single(value, flags) {
|
|
9320
|
+
if (!flags.key || !flags.commit) throw new Error(`verify-image ${value} needs --key <action key> and --commit <sha>.`);
|
|
9321
|
+
if (!COMMIT.test(flags.commit)) throw new Error(`--commit "${flags.commit}" is not a 40-hex commit.`);
|
|
9322
|
+
const image = parseImageReference(value, "verify-image");
|
|
9323
|
+
const misnamed = (0, import_contracts5.actionPackageRefusal)(flags.key, image.repository.ref);
|
|
9324
|
+
if (misnamed !== null) throw new Error(misnamed);
|
|
9325
|
+
return {
|
|
9326
|
+
key: flags.key,
|
|
9327
|
+
image,
|
|
9328
|
+
provenance: {
|
|
9329
|
+
repository: (0, import_contracts5.actionSourceRepository)(flags.key),
|
|
9330
|
+
commit: flags.commit
|
|
9331
|
+
},
|
|
9332
|
+
label: `--key ${flags.key}`
|
|
9333
|
+
};
|
|
9334
|
+
}
|
|
9335
|
+
__name(single, "single");
|
|
9336
|
+
async function fromRelease(path) {
|
|
9337
|
+
let value;
|
|
9338
|
+
try {
|
|
9339
|
+
value = parseYaml3(readFileSync3(path, "utf8"));
|
|
9340
|
+
} catch (cause) {
|
|
9341
|
+
throw new Error(`--from ${path} could not be read as YAML. (${cause instanceof Error ? cause.message : String(cause)})`);
|
|
9342
|
+
}
|
|
9343
|
+
const candidates = [];
|
|
9344
|
+
for (const action of (0, import_contracts5.parseCatalogReleaseSpec)(value).actions) {
|
|
9345
|
+
const label = `${path}'s ${action.key}`;
|
|
9346
|
+
const misnamed = (0, import_contracts5.actionPackageRefusal)(action.key, action.artifactRef);
|
|
9347
|
+
if (misnamed !== null) throw new Error(`${label}: ${misnamed}`);
|
|
9348
|
+
if (!isDigest(action.digest)) throw new Error(`${label}: "${action.digest}" is not a digest.`);
|
|
9349
|
+
const repository = parseRepository(action.artifactRef, label);
|
|
9350
|
+
const read = await readArtifactDocument(repository, action.digest);
|
|
9351
|
+
const document = isMapping2(read) ? read : {};
|
|
9352
|
+
const schemaVersion = document.schemaVersion;
|
|
9353
|
+
if (schemaVersion === import_contracts5.CATALOG_ACTION_ARTIFACT_SCHEMA_V1) continue;
|
|
9354
|
+
if (schemaVersion !== import_contracts5.CATALOG_ACTION_ARTIFACT_SCHEMA_V2) {
|
|
9355
|
+
throw new Error(`${label}: ${repository.ref}@${action.digest} declares schemaVersion ${JSON.stringify(schemaVersion)}; this CLI reads ${import_contracts5.CATALOG_ACTION_ARTIFACT_SCHEMA_V1} and ${import_contracts5.CATALOG_ACTION_ARTIFACT_SCHEMA_V2}.`);
|
|
9356
|
+
}
|
|
9357
|
+
const image = isMapping2(document.image) ? document.image.digest : void 0;
|
|
9358
|
+
const recorded = isMapping2(document.provenance) ? document.provenance : {};
|
|
9359
|
+
if (typeof image !== "string" || typeof recorded.repository !== "string" || typeof recorded.commit !== "string") {
|
|
9360
|
+
throw new Error(`${label}: its ${import_contracts5.CATALOG_ACTION_ARTIFACT_SCHEMA_V2} artifact carries no image digest or no provenance.`);
|
|
9361
|
+
}
|
|
9362
|
+
candidates.push({
|
|
9363
|
+
key: action.key,
|
|
9364
|
+
// ★ The image lives in the artifact's own package (D2) — the artifact names a digest, never a place.
|
|
9365
|
+
image: parseImageReference(`${repository.ref}@${image}`, label),
|
|
9366
|
+
provenance: {
|
|
9367
|
+
repository: recorded.repository,
|
|
9368
|
+
commit: recorded.commit
|
|
9369
|
+
},
|
|
9370
|
+
label
|
|
9371
|
+
});
|
|
9372
|
+
}
|
|
9373
|
+
return candidates;
|
|
9374
|
+
}
|
|
9375
|
+
__name(fromRelease, "fromRelease");
|
|
9376
|
+
async function runVerifyImage(argv) {
|
|
9377
|
+
const image = argv[0] !== void 0 && !argv[0].startsWith("--") ? argv[0] : void 0;
|
|
9378
|
+
const { single: flags } = parseCatalogFlags(image === void 0 ? argv : argv.slice(1), [
|
|
9379
|
+
"key",
|
|
9380
|
+
"commit",
|
|
9381
|
+
"from"
|
|
9382
|
+
]);
|
|
9383
|
+
if (image !== void 0 && flags.from !== void 0) {
|
|
9384
|
+
throw new Error("An image and --from are alternatives: verify one image, or every engine action release.yaml names.");
|
|
9385
|
+
}
|
|
9386
|
+
if (image === void 0 && flags.from === void 0) {
|
|
9387
|
+
throw new Error(`Name an image or a release. Usage: ${VERIFY_IMAGE_USAGE}`);
|
|
9388
|
+
}
|
|
9389
|
+
if (flags.from !== void 0 && (flags.key !== void 0 || flags.commit !== void 0)) {
|
|
9390
|
+
throw new Error("--key and --commit are read from each artifact when --from is given; pass one or the other.");
|
|
9391
|
+
}
|
|
9392
|
+
const candidates = image !== void 0 ? [
|
|
9393
|
+
single(image, flags)
|
|
9394
|
+
] : await fromRelease(flags.from);
|
|
9395
|
+
for (const candidate of candidates) {
|
|
9396
|
+
const refusal = await imageRefusal(candidate.image, candidate.key, candidate.provenance);
|
|
9397
|
+
if (refusal !== null) throw new Error(`${candidate.label}: ${refusal} Nothing was signed.`);
|
|
9398
|
+
}
|
|
9399
|
+
for (const candidate of candidates) {
|
|
9400
|
+
process.stderr.write(`\u2713 ${candidate.key}: ${candidate.image.ref} \u2014 built in ${candidate.provenance.repository} at ${candidate.provenance.commit}
|
|
9401
|
+
`);
|
|
9402
|
+
process.stdout.write(`${candidate.image.ref}
|
|
9403
|
+
`);
|
|
9404
|
+
}
|
|
9405
|
+
if (candidates.length === 0) process.stderr.write(`\u2713 ${flags.from} names no engine action \u2014 no image to sign.
|
|
9406
|
+
`);
|
|
9407
|
+
}
|
|
9408
|
+
__name(runVerifyImage, "runVerifyImage");
|
|
9409
|
+
|
|
8057
9410
|
// src/catalog/index.ts
|
|
8058
9411
|
var CATALOG_USAGE = `runveric catalog \u2014 publish first-party catalog artifacts (docs/127)
|
|
8059
9412
|
|
|
8060
9413
|
${PUBLISH_ACTION_USAGE}
|
|
8061
|
-
Publish one action's manifest, verbatim, as an artifact
|
|
9414
|
+
Publish one action's manifest, verbatim, as an artifact \u2014 with --image, an engine action's
|
|
9415
|
+
artifact naming its image by digest. stdout: <key>=<repository>@<digest>
|
|
8062
9416
|
|
|
8063
9417
|
${PUBLISH_RELEASE_USAGE}
|
|
8064
9418
|
Publish a release naming each action artifact by digest. stdout: <repository>@<digest>
|
|
8065
9419
|
|
|
9420
|
+
${VERIFY_IMAGE_USAGE}
|
|
9421
|
+
Judge an engine action's image by the server's rule before it is signed.
|
|
9422
|
+
stdout: one <repository>@<digest> per image that passed
|
|
9423
|
+
|
|
8066
9424
|
Credentials: GHCR_TOKEN (write:packages), or in a workflow GITHUB_TOKEN with packages: write.
|
|
8067
9425
|
Provenance: --repository/--commit, else GITHUB_SERVER_URL/GITHUB_REPOSITORY and GITHUB_SHA, else git.`;
|
|
8068
9426
|
var SUBCOMMANDS = {
|
|
8069
9427
|
"publish-action": runPublishAction,
|
|
8070
|
-
"publish-release": runPublishRelease
|
|
9428
|
+
"publish-release": runPublishRelease,
|
|
9429
|
+
"verify-image": runVerifyImage
|
|
8071
9430
|
};
|
|
8072
9431
|
async function runCatalog(argv) {
|
|
8073
9432
|
const [subcommand, ...rest] = argv;
|
|
@@ -8078,7 +9437,7 @@ async function runCatalog(argv) {
|
|
|
8078
9437
|
}
|
|
8079
9438
|
const run3 = SUBCOMMANDS[subcommand];
|
|
8080
9439
|
if (run3 === void 0) {
|
|
8081
|
-
printError(`\u2717 "catalog ${subcommand}" is not a command. There are
|
|
9440
|
+
printError(`\u2717 "catalog ${subcommand}" is not a command. There are ${Object.keys(SUBCOMMANDS).length}: ${Object.keys(SUBCOMMANDS).join(", ")}.`);
|
|
8082
9441
|
return 1;
|
|
8083
9442
|
}
|
|
8084
9443
|
try {
|
|
@@ -8152,7 +9511,7 @@ function toPackagePath(root, full) {
|
|
|
8152
9511
|
__name(toPackagePath, "toPackagePath");
|
|
8153
9512
|
|
|
8154
9513
|
// src/check.ts
|
|
8155
|
-
var
|
|
9514
|
+
var import_contracts6 = __toESM(require_dist());
|
|
8156
9515
|
async function runCheck(options) {
|
|
8157
9516
|
const directory = resolve2(options.directory ?? ".");
|
|
8158
9517
|
let files;
|
|
@@ -8176,7 +9535,7 @@ async function runCheck(options) {
|
|
|
8176
9535
|
print(style.red("This package would be REFUSED at import."));
|
|
8177
9536
|
} else if (report.lintBlocked) {
|
|
8178
9537
|
print();
|
|
8179
|
-
print(style.red("This package would be ACCEPTED at import \u2014 and then misbehave.") + ` The errors above are not things ${
|
|
9538
|
+
print(style.red("This package would be ACCEPTED at import \u2014 and then misbehave.") + ` The errors above are not things ${import_contracts6.BRAND_SHORT_NAME} checks; they are things that go wrong at run time, silently.`);
|
|
8180
9539
|
}
|
|
8181
9540
|
if (report.advisoryCount > 0) {
|
|
8182
9541
|
print();
|
|
@@ -8196,7 +9555,7 @@ async function runCheck(options) {
|
|
|
8196
9555
|
__name(runCheck, "runCheck");
|
|
8197
9556
|
|
|
8198
9557
|
// src/init.ts
|
|
8199
|
-
var
|
|
9558
|
+
var import_contracts7 = __toESM(require_dist());
|
|
8200
9559
|
var import_action_manifest2 = __toESM(require_dist2());
|
|
8201
9560
|
import { mkdir, writeFile } from "fs/promises";
|
|
8202
9561
|
import { createInterface } from "readline/promises";
|
|
@@ -8265,9 +9624,9 @@ async function resolveId(supplied, ask) {
|
|
|
8265
9624
|
}
|
|
8266
9625
|
__name(resolveId, "resolveId");
|
|
8267
9626
|
async function resolveInterpreter(supplied, ask) {
|
|
8268
|
-
const value = supplied?.trim() || await ask?.(`Interpreter (${
|
|
9627
|
+
const value = supplied?.trim() || await ask?.(`Interpreter (${import_contracts7.PACKAGE_INTERPRETERS.join(" / ")})`, "bash") || "bash";
|
|
8269
9628
|
if (!isInterpreter(value)) {
|
|
8270
|
-
printError(style.red(`"${value}" is not an interpreter ${
|
|
9629
|
+
printError(style.red(`"${value}" is not an interpreter ${import_contracts7.BRAND_SHORT_NAME} runs.`) + ` The runner image ships ${import_contracts7.PACKAGE_INTERPRETERS.join(", ")}.`);
|
|
8271
9630
|
return null;
|
|
8272
9631
|
}
|
|
8273
9632
|
return value;
|
|
@@ -8288,7 +9647,7 @@ function prompter() {
|
|
|
8288
9647
|
}
|
|
8289
9648
|
__name(prompter, "prompter");
|
|
8290
9649
|
function isInterpreter(value) {
|
|
8291
|
-
return
|
|
9650
|
+
return import_contracts7.PACKAGE_INTERPRETERS.includes(value);
|
|
8292
9651
|
}
|
|
8293
9652
|
__name(isInterpreter, "isInterpreter");
|
|
8294
9653
|
function titleCase(value) {
|
|
@@ -8298,7 +9657,7 @@ __name(titleCase, "titleCase");
|
|
|
8298
9657
|
|
|
8299
9658
|
// src/publish.ts
|
|
8300
9659
|
var import_action_manifest3 = __toESM(require_dist2());
|
|
8301
|
-
var
|
|
9660
|
+
var import_contracts8 = __toESM(require_dist());
|
|
8302
9661
|
import { resolve as resolve4 } from "path";
|
|
8303
9662
|
|
|
8304
9663
|
// src/renamed-variable.ts
|
|
@@ -8310,15 +9669,15 @@ function renamedVariableRefusal(current, retired, env = process.env) {
|
|
|
8310
9669
|
__name(renamedVariableRefusal, "renamedVariableRefusal");
|
|
8311
9670
|
|
|
8312
9671
|
// src/publish.ts
|
|
8313
|
-
var TOKEN_ENV =
|
|
8314
|
-
var URL_ENV =
|
|
9672
|
+
var TOKEN_ENV = import_contracts8.AUTHORING_CLI_ENV.token;
|
|
9673
|
+
var URL_ENV = import_contracts8.AUTHORING_CLI_ENV.url;
|
|
8315
9674
|
async function runPublish(options) {
|
|
8316
9675
|
const directory = resolve4(options.directory ?? ".");
|
|
8317
9676
|
const baseUrl = (options.to ?? process.env[URL_ENV] ?? "").trim().replace(/\/+$/, "");
|
|
8318
9677
|
const token2 = (options.token ?? process.env[TOKEN_ENV] ?? "").trim();
|
|
8319
9678
|
const stale = [
|
|
8320
|
-
options.to === void 0 ? renamedVariableRefusal(URL_ENV,
|
|
8321
|
-
options.token === void 0 ? renamedVariableRefusal(TOKEN_ENV,
|
|
9679
|
+
options.to === void 0 ? renamedVariableRefusal(URL_ENV, import_contracts8.RETIRED_AUTHORING_CLI_ENV.url) : null,
|
|
9680
|
+
options.token === void 0 ? renamedVariableRefusal(TOKEN_ENV, import_contracts8.RETIRED_AUTHORING_CLI_ENV.token) : null
|
|
8322
9681
|
].filter((sentence) => sentence !== null);
|
|
8323
9682
|
if (stale.length > 0) {
|
|
8324
9683
|
for (const sentence of stale) printError(style.red(sentence));
|
|
@@ -8329,7 +9688,7 @@ async function runPublish(options) {
|
|
|
8329
9688
|
return 1;
|
|
8330
9689
|
}
|
|
8331
9690
|
if (!token2) {
|
|
8332
|
-
printError(style.red(`Publishing needs ${
|
|
9691
|
+
printError(style.red(`Publishing needs ${import_contracts8.BRAND_ARTICLE} ${import_contracts8.BRAND_SHORT_NAME} access token.`) + ` Set ${TOKEN_ENV}, or pass --token. (init, check and test need no account at all.)`);
|
|
8333
9692
|
return 1;
|
|
8334
9693
|
}
|
|
8335
9694
|
let files;
|
|
@@ -8349,7 +9708,7 @@ async function runPublish(options) {
|
|
|
8349
9708
|
errors: report.errorCount,
|
|
8350
9709
|
warnings: report.warningCount
|
|
8351
9710
|
});
|
|
8352
|
-
printError(style.red("\nNot published.") + (report.validation.ok ? ` ${
|
|
9711
|
+
printError(style.red("\nNot published.") + (report.validation.ok ? ` ${import_contracts8.BRAND_SHORT_NAME} would accept this, but the problems above make it misbehave at run time. Fix them, or pass --force if you disagree.` : " Fix the errors above and publish again."));
|
|
8353
9712
|
return 1;
|
|
8354
9713
|
}
|
|
8355
9714
|
if (report.advisoryCount > 0) {
|
|
@@ -8396,7 +9755,7 @@ Publish refused (${response.status}).`));
|
|
|
8396
9755
|
try {
|
|
8397
9756
|
version2 = JSON.parse(text);
|
|
8398
9757
|
} catch {
|
|
8399
|
-
printError(style.red(`${
|
|
9758
|
+
printError(style.red(`${import_contracts8.BRAND_SHORT_NAME} accepted the package but returned a response we cannot read.`));
|
|
8400
9759
|
return 1;
|
|
8401
9760
|
}
|
|
8402
9761
|
print();
|
|
@@ -8405,7 +9764,7 @@ Publish refused (${response.status}).`));
|
|
|
8405
9764
|
print(` content digest ${version2.contentDigest}`);
|
|
8406
9765
|
print(` tier ${version2.tier} ${style.grey(`(${version2.provenance})`)}`);
|
|
8407
9766
|
print();
|
|
8408
|
-
print(style.grey(`It is an immutable version now. Adopt it in ${
|
|
9767
|
+
print(style.grey(`It is an immutable version now. Adopt it in ${import_contracts8.BRAND_SHORT_NAME} to put it in the catalog \u2014 publishing does not adopt, so nobody can run it until somebody chooses to.`));
|
|
8409
9768
|
print();
|
|
8410
9769
|
return 0;
|
|
8411
9770
|
}
|
|
@@ -8417,11 +9776,11 @@ function formatProblem(text) {
|
|
|
8417
9776
|
} catch {
|
|
8418
9777
|
return ` ${text}`;
|
|
8419
9778
|
}
|
|
8420
|
-
const problem = (0,
|
|
9779
|
+
const problem = (0, import_contracts8.parseProblemDocument)(parsed);
|
|
8421
9780
|
if (!problem) return ` ${text}`;
|
|
8422
9781
|
const lines = [];
|
|
8423
9782
|
if (problem.detail) lines.push(` ${problem.detail}`);
|
|
8424
|
-
for (const error of (0,
|
|
9783
|
+
for (const error of (0, import_contracts8.problemFieldErrors)(problem)) {
|
|
8425
9784
|
lines.push(error.field ? ` ${style.bold(error.field)}: ${error.message}` : ` ${error.message}`);
|
|
8426
9785
|
}
|
|
8427
9786
|
return lines.length > 0 ? lines.join("\n") : ` ${text}`;
|
|
@@ -8429,12 +9788,12 @@ function formatProblem(text) {
|
|
|
8429
9788
|
__name(formatProblem, "formatProblem");
|
|
8430
9789
|
|
|
8431
9790
|
// src/runner-image.ts
|
|
8432
|
-
var
|
|
9791
|
+
var import_contracts9 = __toESM(require_dist());
|
|
8433
9792
|
import { execFile } from "child_process";
|
|
8434
9793
|
import { promisify } from "util";
|
|
8435
9794
|
var run = promisify(execFile);
|
|
8436
9795
|
var LOCAL_RUNNER_IMAGE = "runveric-package-runner:local";
|
|
8437
|
-
var RUNNER_IMAGE_ENV =
|
|
9796
|
+
var RUNNER_IMAGE_ENV = import_contracts9.AUTHORING_CLI_ENV.runnerImage;
|
|
8438
9797
|
var RenamedVariableError = class extends Error {
|
|
8439
9798
|
static {
|
|
8440
9799
|
__name(this, "RenamedVariableError");
|
|
@@ -8451,7 +9810,7 @@ function resolveRunnerImage(flag) {
|
|
|
8451
9810
|
reference: configured,
|
|
8452
9811
|
origin: "environment"
|
|
8453
9812
|
};
|
|
8454
|
-
const stale = renamedVariableRefusal(RUNNER_IMAGE_ENV,
|
|
9813
|
+
const stale = renamedVariableRefusal(RUNNER_IMAGE_ENV, import_contracts9.RETIRED_AUTHORING_CLI_ENV.runnerImage);
|
|
8455
9814
|
if (stale) throw new RenamedVariableError(stale);
|
|
8456
9815
|
return {
|
|
8457
9816
|
reference: LOCAL_RUNNER_IMAGE,
|
|
@@ -8466,7 +9825,7 @@ function runnerImageNote(image) {
|
|
|
8466
9825
|
case "environment":
|
|
8467
9826
|
return `from ${RUNNER_IMAGE_ENV}`;
|
|
8468
9827
|
case "local-build":
|
|
8469
|
-
return `locally built \u2014 NOT the image your ${
|
|
9828
|
+
return `locally built \u2014 NOT the image your ${import_contracts9.BRAND_SHORT_NAME} runs; set ${RUNNER_IMAGE_ENV} to match it`;
|
|
8470
9829
|
}
|
|
8471
9830
|
}
|
|
8472
9831
|
__name(runnerImageNote, "runnerImageNote");
|
|
@@ -8483,7 +9842,7 @@ async function assertDockerAvailable() {
|
|
|
8483
9842
|
"{{.Server.Version}}"
|
|
8484
9843
|
]);
|
|
8485
9844
|
} catch {
|
|
8486
|
-
throw new DockerMissingError(`Docker is not available. \`runveric test\` runs your package in the real ${
|
|
9845
|
+
throw new DockerMissingError(`Docker is not available. \`runveric test\` runs your package in the real ${import_contracts9.BRAND_SHORT_NAME} runner image, which needs a container runtime \u2014 install Docker Desktop (or start it), then try again. \`runveric check\` needs nothing and still works.`);
|
|
8487
9846
|
}
|
|
8488
9847
|
}
|
|
8489
9848
|
__name(assertDockerAvailable, "assertDockerAvailable");
|
|
@@ -8576,7 +9935,7 @@ ${message.trim()}`);
|
|
|
8576
9935
|
__name(azJson, "azJson");
|
|
8577
9936
|
|
|
8578
9937
|
// src/test.ts
|
|
8579
|
-
var
|
|
9938
|
+
var import_contracts10 = __toESM(require_dist());
|
|
8580
9939
|
var PHASES = [
|
|
8581
9940
|
"validate",
|
|
8582
9941
|
"run",
|
|
@@ -8593,7 +9952,7 @@ async function runTest(options) {
|
|
|
8593
9952
|
const directory = resolve5(options.directory ?? ".");
|
|
8594
9953
|
const phase = options.phase ?? "run";
|
|
8595
9954
|
if (!PHASES.includes(phase)) {
|
|
8596
|
-
printError(style.red(`"${options.phase}" is not a phase.`) + ` ${
|
|
9955
|
+
printError(style.red(`"${options.phase}" is not a phase.`) + ` ${import_contracts10.BRAND_SHORT_NAME} runs ${PHASES.join(", ")} \u2014 one at a time, so you can read each one's result.`);
|
|
8597
9956
|
return 1;
|
|
8598
9957
|
}
|
|
8599
9958
|
let files;
|
|
@@ -8665,9 +10024,9 @@ async function runTest(options) {
|
|
|
8665
10024
|
print(` runner image ${image.reference} ${style.grey(`(${runnerImageNote(image)})`)}`);
|
|
8666
10025
|
print(` interpreter ${interpreter}@${manifest.runtime.version}`);
|
|
8667
10026
|
print(` entrypoint ${entrypoint}${import_action_manifest4.PACKAGE_INTERPRETER_LAUNCH[interpreter].entryFile}`);
|
|
8668
|
-
print(` identity ${credential ? `${credential.account.name} ${style.grey(`\u2014 YOUR access, not ${
|
|
10027
|
+
print(` identity ${credential ? `${credential.account.name} ${style.grey(`\u2014 YOUR access, not ${import_contracts10.BRAND_SHORT_NAME}'s brokered least-privilege identity`)}` : style.grey("none (--no-credential)")}`);
|
|
8669
10028
|
if (manifest.requiresNetwork) {
|
|
8670
|
-
print(` network ${style.yellow("open")} ${style.grey(`\u2014 your allowlist (${(manifest.egressAllowlist ?? []).join(", ")}) is NOT enforced here; ${
|
|
10029
|
+
print(` network ${style.yellow("open")} ${style.grey(`\u2014 your allowlist (${(manifest.egressAllowlist ?? []).join(", ")}) is NOT enforced here; ${import_contracts10.BRAND_SHORT_NAME} enforces it`)}`);
|
|
8671
10030
|
} else {
|
|
8672
10031
|
print(` network ${style.grey("none \u2014 this package declares requiresNetwork: false")}`);
|
|
8673
10032
|
}
|
|
@@ -8775,7 +10134,7 @@ async function materialize(workspace, input) {
|
|
|
8775
10134
|
await writeFile2(target, contents);
|
|
8776
10135
|
}
|
|
8777
10136
|
const context = {
|
|
8778
|
-
protocolVersion:
|
|
10137
|
+
protocolVersion: import_contracts10.PACKAGE_EXECUTION_PROTOCOL_VERSION,
|
|
8779
10138
|
// A recognisable id rather than a random uuid: it appears in the package's own log lines,
|
|
8780
10139
|
// and "local-test" tells the reader instantly that this was not a real run.
|
|
8781
10140
|
executionId: "local-test",
|
|
@@ -8801,7 +10160,7 @@ async function runContainer(options) {
|
|
|
8801
10160
|
const launch = import_action_manifest4.PACKAGE_INTERPRETER_LAUNCH[options.interpreter];
|
|
8802
10161
|
const script = `${CONTAINER.packageRoot}/${options.entrypoint}${launch.entryFile}`;
|
|
8803
10162
|
const environment = {
|
|
8804
|
-
RUNVERIC_PROTOCOL_VERSION:
|
|
10163
|
+
RUNVERIC_PROTOCOL_VERSION: import_contracts10.PACKAGE_RESULT_PROTOCOL_VERSION,
|
|
8805
10164
|
RUNVERIC_PHASE: options.phase,
|
|
8806
10165
|
RUNVERIC_CONTEXT_FILE: `${CONTAINER.input}/context.json`,
|
|
8807
10166
|
RUNVERIC_PARAMETERS_FILE: `${CONTAINER.input}/parameters.json`,
|
|
@@ -8928,13 +10287,13 @@ function emitLine(line, stderr, onEvent) {
|
|
|
8928
10287
|
__name(emitLine, "emitLine");
|
|
8929
10288
|
async function reportOutcome(options) {
|
|
8930
10289
|
if (options.exit.timedOut) {
|
|
8931
|
-
printError(style.red("\nThe package did not finish within 15 minutes and was killed.") + ` ${
|
|
10290
|
+
printError(style.red("\nThe package did not finish within 15 minutes and was killed.") + ` ${import_contracts10.BRAND_SHORT_NAME} enforces the \`executionTimeout\` in your manifest; this is the local ceiling.`);
|
|
8932
10291
|
return 1;
|
|
8933
10292
|
}
|
|
8934
10293
|
const exists = await stat2(options.resultPath).catch(() => null);
|
|
8935
10294
|
if (!exists?.isFile() || exists.size === 0) {
|
|
8936
10295
|
printError(style.red("\nThe package wrote no result.") + `
|
|
8937
|
-
result.json is the only channel ${
|
|
10296
|
+
result.json is the only channel ${import_contracts10.BRAND_SHORT_NAME} reads. Exiting ${options.exit.code ?? "with a signal"} without writing $RUNVERIC_RESULT_FILE is a FAILED run, whatever the script printed.
|
|
8938
10297
|
Write it as the last thing your script does, on every path \u2014 including the ones that fail.`);
|
|
8939
10298
|
return 1;
|
|
8940
10299
|
}
|
|
@@ -8942,7 +10301,7 @@ async function reportOutcome(options) {
|
|
|
8942
10301
|
try {
|
|
8943
10302
|
parsed = JSON.parse(await readFile2(options.resultPath, "utf8"));
|
|
8944
10303
|
} catch {
|
|
8945
|
-
printError(style.red("\nresult.json is not valid JSON.") + ` ${
|
|
10304
|
+
printError(style.red("\nresult.json is not valid JSON.") + ` ${import_contracts10.BRAND_SHORT_NAME} refuses the run rather than guessing what the package meant.`);
|
|
8946
10305
|
return 1;
|
|
8947
10306
|
}
|
|
8948
10307
|
let result;
|
|
@@ -8950,14 +10309,14 @@ async function reportOutcome(options) {
|
|
|
8950
10309
|
result = (0, import_action_manifest4.validatePackageResult)(parsed, options.phase);
|
|
8951
10310
|
} catch (error) {
|
|
8952
10311
|
printError(style.red(`
|
|
8953
|
-
${
|
|
10312
|
+
${import_contracts10.BRAND_SHORT_NAME} would REFUSE this result.`) + `
|
|
8954
10313
|
${error instanceof Error ? error.message : String(error)}
|
|
8955
10314
|
This is the same check the control plane runs, so fixing it here fixes it there.`);
|
|
8956
10315
|
return 1;
|
|
8957
10316
|
}
|
|
8958
10317
|
printResult(result);
|
|
8959
10318
|
if (options.exit.code !== 0) {
|
|
8960
|
-
print(style.yellow(`The package exited ${options.exit.code} but wrote a valid result. ${
|
|
10319
|
+
print(style.yellow(`The package exited ${options.exit.code} but wrote a valid result. ${import_contracts10.BRAND_SHORT_NAME} reads the result, not the exit code \u2014 but a non-zero exit usually means something failed after the result was written.`));
|
|
8961
10320
|
print();
|
|
8962
10321
|
}
|
|
8963
10322
|
return result.status === "succeeded" ? 0 : 1;
|
|
@@ -8984,9 +10343,9 @@ async function readJsonFile(path) {
|
|
|
8984
10343
|
__name(readJsonFile, "readJsonFile");
|
|
8985
10344
|
|
|
8986
10345
|
// src/main.ts
|
|
8987
|
-
var
|
|
10346
|
+
var import_contracts11 = __toESM(require_dist());
|
|
8988
10347
|
var USAGE = `
|
|
8989
|
-
${style.bold("runveric")} \u2014 author ${
|
|
10348
|
+
${style.bold("runveric")} \u2014 author ${import_contracts11.BRAND_ARTICLE} ${import_contracts11.BRAND_SHORT_NAME} action, without pushing anything.
|
|
8990
10349
|
|
|
8991
10350
|
${style.bold("USAGE")}
|
|
8992
10351
|
runveric <command> [options]
|
|
@@ -8994,8 +10353,8 @@ ${style.bold("USAGE")}
|
|
|
8994
10353
|
${style.bold("COMMANDS")}
|
|
8995
10354
|
init [directory] Scaffold a working action. It passes check and test immediately.
|
|
8996
10355
|
check Validate the package. Offline \u2014 no account, no cloud, no network.
|
|
8997
|
-
test Run one phase in the real ${
|
|
8998
|
-
publish Upload it to ${
|
|
10356
|
+
test Run one phase in the real ${import_contracts11.BRAND_SHORT_NAME} runner image.
|
|
10357
|
+
publish Upload it to ${import_contracts11.BRAND_SHORT_NAME} as an authored version. Needs an account.
|
|
8999
10358
|
catalog <command> Publish first-party catalog artifacts. Not for authoring: see \`runveric catalog --help\`.
|
|
9000
10359
|
|
|
9001
10360
|
${style.bold("init")}
|
|
@@ -9019,9 +10378,9 @@ ${style.bold("test")}
|
|
|
9019
10378
|
--keep Keep the materialized /runveric tree for inspection.
|
|
9020
10379
|
|
|
9021
10380
|
${style.bold("publish")}
|
|
9022
|
-
--to <url> Your ${
|
|
10381
|
+
--to <url> Your ${import_contracts11.BRAND_SHORT_NAME} URL. Defaults to $${URL_ENV}.
|
|
9023
10382
|
--token <token> Access token. Defaults to $${TOKEN_ENV}.
|
|
9024
|
-
--force Publish despite lint errors. Never bypasses ${
|
|
10383
|
+
--force Publish despite lint errors. Never bypasses ${import_contracts11.BRAND_SHORT_NAME}'s validation.
|
|
9025
10384
|
|
|
9026
10385
|
${style.bold("EVERYWHERE")}
|
|
9027
10386
|
--dir <path> The package directory. Defaults to the current directory.
|