Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/seven-moments-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

Require cartesi-machine 0.22. Machines stored by 0.21 can't be loaded by 0.22: rebuild and redeploy every application.
29 changes: 29 additions & 0 deletions .github/workflows/cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ on:
pull_request:
paths:
- ".github/workflows/cli.yaml"
- ".github/workflows/sdk.yaml"
- "apps/cli/**"
- "packages/sdk/**"
- "packages/tsconfig/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
Expand All @@ -13,11 +15,21 @@ permissions:
packages: write
pull-requests: write
jobs:
sdk:
uses: ./.github/workflows/sdk.yaml
secrets: inherit
permissions:
contents: read
packages: write
id-token: write
actions: write
build:
needs: sdk
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
SDK_TAG: pr-${{ github.event.pull_request.number }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -28,6 +40,20 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Login to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Retag SDK images
run: |
for image in sdk rollups-runtime rollups-database; do
docker pull "ghcr.io/cartesi/$image:$SDK_TAG"
docker tag "ghcr.io/cartesi/$image:$SDK_TAG" "cartesi/$image:$SDK_TAG"
done

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
Expand All @@ -45,6 +71,9 @@ jobs:

- name: Test
run: bun test apps/cli/
env:
CARTESI_TEST_SDK: cartesi/sdk:${{ env.SDK_TAG }}
CARTESI_TEST_RUNTIME_VERSION: ${{ env.SDK_TAG }}

- name: Coverage Report
uses: 70-10/bun-coverage-report-action@6173866ce2a31456a726ff3f4c91f230bd94a9e9 # v1.0.3
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/sdk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ on:
required: true
DOCKERHUB_TOKEN:
required: true
pull_request:
paths:
- ".github/workflows/sdk.yaml"
- "packages/sdk/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
group: sdk-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
Expand Down Expand Up @@ -83,6 +79,9 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Fetch rollups-node packages
run: ./packages/sdk/scripts/fetch-rollups-node.sh

- name: Build and push
uses: docker/bake-action@018cb6412ab401ebaa809aa5f85966b74628600f # v7.4.0
if: ${{ !startsWith(github.ref, 'refs/tags/sdk@') }}
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/src/exec/cartesi-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
type ExecaOptionsDockerFallback,
} from "./util.js";

export const requiredVersion = new Range("^0.21.0");
export const requiredVersion = new Range("^0.22.0");

export const boot = (
args: readonly string[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ export type Layout = {
at: number; // offset of data, the rest is zeros
data: Buffer;
};
// TODO: the machine-tool of rollups-node v2.0.0-alpha.13 only looks for the
// accounts drive among the flash drives, unskip once it finds nvrams too
skip?: boolean;
};

const scratchDrive = `
Expand Down Expand Up @@ -76,7 +73,6 @@ accounts_drive = true
`,
label: "accounts",
device: "/dev/uio0",
skip: true,
},
{
name: "the beginning of a larger nvram",
Expand All @@ -96,7 +92,6 @@ accounts_drive_size = "4Mi"
label: "state",
device: "/dev/uio1",
accountsSize: 4 * MiB,
skip: true,
},
{
// like a DEX, which memory-maps its state after the accounts, from an image
Expand All @@ -118,6 +113,5 @@ accounts_drive_size = "4Mi"
at: 4 * MiB,
data: Buffer.alloc(8 * MiB, 0xab),
},
skip: true,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ ${layout.accountsSize ? `ACCOUNTS_SIZE = "${layout.accountsSize}"` : ""}
};

layouts.forEach((layout, index) => {
const describeLayout = layout.skip ? describe.skip : describe;

describeLayout(`emergency withdrawal from ${layout.name}`, () => {
describe(`emergency withdrawal from ${layout.name}`, () => {
const projectName = `layouts-${index}-${process.pid}`;
let appDir: string;
let cleanup: () => void;
Expand Down
10 changes: 6 additions & 4 deletions apps/cli/tests/integration/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ export async function createTemporaryCartesiApplication(options?: {
// Build with the same image the snapshot readers use. Without this the
// build falls back to the released SDK while the readers use TEST_SDK,
// and a snapshot written by one emulator is rejected by the other.
fs.appendFileSync(
path.join(appDir, "cartesi.toml"),
`\nsdk = "${TEST_SDK}"\n`,
);
// Prepended, so the key stays top-level whatever tables the config ends with.
const configPath = path.join(appDir, "cartesi.toml");
const config = fs.existsSync(configPath)
? fs.readFileSync(configPath, "utf-8")
: "";
fs.writeFileSync(configPath, `sdk = "${TEST_SDK}"\n${config}`);

// Change directory into the created application
process.chdir(appDir);
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/tests/integration/machine/nvram.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const found = await cartesiMachine.version({
const supported =
found !== null && satisfies(found.format(), cartesiMachine.requiredVersion);

// no sdk key here: the helper appends `sdk = "${TEST_SDK}"` itself, and TOML rejects duplicates
// no sdk key here: the helper prepends `sdk = "${TEST_SDK}"` itself, and TOML rejects duplicates
const CONFIG = `[nvrams.input]
size = "4Ki"

Expand Down Expand Up @@ -54,7 +54,7 @@ describe.skipIf(!supported)("when booting a machine with nvrams", () => {
* Boots the built application with a different entrypoint, the way the shell command does.
*/
const boot = async (command: string) => {
// the app's own config, which carries the sdk pin the helper appended
// the app's own config, which carries the sdk pin the helper prepended
const config = parse([
fs.readFileSync(path.join(app.appDir, "cartesi.toml"), "utf-8"),
]);
Expand Down
8 changes: 4 additions & 4 deletions apps/cli/tests/unit/exec/cartesi-machine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import {
const semver = (version: string) => parse(version) as SemVer;

describe("requiredVersion", () => {
it.each(["0.21.0", "0.21.3"])("should accept %s", (version) => {
it.each(["0.22.0", "0.22.3"])("should accept %s", (version) => {
expect(satisfies(version, requiredVersion)).toBeTruthy();
});

it.each(["0.20.0", "0.20.9", "0.22.0", "1.0.0"])(
it.each(["0.21.0", "0.21.9", "0.23.0", "1.0.0"])(
"should reject %s",
(version) => {
expect(satisfies(version, requiredVersion)).toBeFalsy();
Expand All @@ -22,11 +22,11 @@ describe("requiredVersion", () => {
});

describe("assertSupported", () => {
it.each(["0.21.0", "0.21.3"])("should accept %s", (version) => {
it.each(["0.22.0", "0.22.3"])("should accept %s", (version) => {
expect(() => assertSupported(semver(version))).not.toThrow();
});

it.each(["0.20.0", "0.22.0"])("should reject %s", (version) => {
it.each(["0.21.0", "0.23.0"])("should reject %s", (version) => {
expect(() => assertSupported(semver(version))).toThrowError(
new UnsupportedVersionError(semver(version)),
);
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build.json
rollups-node/
34 changes: 13 additions & 21 deletions packages/sdk/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

################################################################################
# base image
FROM ${CARTESI_BASE_IMAGE} AS base

Check warning on line 8 in packages/sdk/Dockerfile

View workflow job for this annotation

GitHub Actions / sdk / build

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG ${CARTESI_BASE_IMAGE} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/
SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF
Expand Down Expand Up @@ -88,7 +88,7 @@
mkdir -p /opt/devnet
curl -fsSL https://github.com/cartesi/dave/releases/download/v${CARTESI_PRT_VERSION}/cartesi-rollups-prt-${CARTESI_PRT_VERSION}-anvil-${FOUNDRY_VERSION}.tar.gz \
-o /tmp/prt-anvil.tar.gz
echo "7e6b6a402b5e384fd6aa56387726cf4cc08783b6350b1c16a71a2e6ff454e583 /tmp/prt-anvil.tar.gz" | sha256sum --check
echo "62500dc3558fbb1f289d99584cd8989d7b42d0c0e7e7a13b8f2d309746e9163e /tmp/prt-anvil.tar.gz" | sha256sum --check
tar -xzO -f /tmp/prt-anvil.tar.gz state.json > /opt/devnet/anvil_state.json
rm /tmp/prt-anvil.tar.gz
echo ${CARTESI_PRT_VERSION} > /opt/devnet/PRT_VERSION
Expand Down Expand Up @@ -160,11 +160,11 @@
ARG TARGETARCH
WORKDIR /tmp
RUN <<EOF
curl -fsSL https://github.com/cartesi/dave/releases/download/v${CARTESI_PRT_VERSION}/cartesi-rollups-prt-${CARTESI_PRT_VERSION}-node-${TARGETARCH}.tar.gz \
curl -fsSL https://github.com/cartesi/dave/releases/download/v${CARTESI_PRT_VERSION}/cartesi-sling-node-${CARTESI_PRT_VERSION}-${TARGETARCH}.tar.gz \
-o ./sling-node.tar.gz;
case "${TARGETARCH}" in
amd64) echo "a69beb8a96aad4eb0e7be1ac492bc6e3e312cbc105456403b14d2889c8364f68 /tmp/sling-node.tar.gz" | sha256sum --check ;;
arm64) echo "c19e932f6b4ac1039af8b0fac2355268397e31cae6302809cad50221d9058cba /tmp/sling-node.tar.gz" | sha256sum --check ;;
amd64) echo "25c04e29a1c3da2dec1cfc02413cae053b6093fe40c264348aeac69b680a0757 /tmp/sling-node.tar.gz" | sha256sum --check ;;
arm64) echo "a15c5df6679186f39c6e634815ecd47d696a947ad0ce66cf1f23b44d81d70b1a /tmp/sling-node.tar.gz" | sha256sum --check ;;
*) echo "unsupported architecture: ${TARGETARCH}"; exit 1 ;;
esac
tar -xvzf /tmp/sling-node.tar.gz -C /usr/local/bin
Expand Down Expand Up @@ -207,24 +207,18 @@
curl -fsSL https://github.com/cartesi/machine-emulator/releases/download/v${CARTESI_MACHINE_EMULATOR_VERSION}/machine-emulator_${TARGETARCH}.deb \
-o /tmp/machine-emulator.deb
case "${TARGETARCH}" in
amd64) echo "5f13034f43454c340062c677146daabe77c587cee1bd60342c95b8ad8f1463a3 /tmp/machine-emulator.deb" | sha256sum --check ;;
arm64) echo "866f0bde2db53b9b8e6a6eac85e5ad4116338379fa25cdfcc5e4bf835f948bb1 /tmp/machine-emulator.deb" | sha256sum --check ;;
amd64) echo "906ae4cd0524ef254ea9a83712e6ad353c36123acae21628fb93c1c47955429a /tmp/machine-emulator.deb" | sha256sum --check ;;
arm64) echo "212710b5ad74e469368cd5f54b006eebde1e8620833acca5be9a845cf74ab2cc /tmp/machine-emulator.deb" | sha256sum --check ;;
*) echo "unsupported architecture: ${TARGETARCH}"; exit 1 ;;
esac
apt-get install -y --no-install-recommends /tmp/machine-emulator.deb
rm /tmp/machine-emulator.deb
cartesi-machine --version-json
EOF

# Install cartesi-rollups-node
# Install cartesi-rollups-node (WIP: built by rollups-node CI, see scripts/fetch-rollups-node.sh)
COPY rollups-node/cartesi-rollups-node_${TARGETARCH}.deb /tmp/cartesi-rollups-node.deb
RUN <<EOF
curl -fsSL https://github.com/cartesi/rollups-node/releases/download/v${CARTESI_ROLLUPS_NODE_VERSION}/cartesi-rollups-node-v${CARTESI_ROLLUPS_NODE_VERSION}_${TARGETARCH}.deb \
-o /tmp/cartesi-rollups-node.deb
case "${TARGETARCH}" in
amd64) echo "5c75b12082bded69e589781715c74ce7ddf433a7ed2fa6f831e92315fa6dc003 /tmp/cartesi-rollups-node.deb" | sha256sum --check ;;
arm64) echo "ab4007baa7ea37ed58957fa94478c5f6e6999ca5234520bbfecb82e9c9c9bab3 /tmp/cartesi-rollups-node.deb" | sha256sum --check ;;
*) echo "unsupported architecture: ${TARGETARCH}"; exit 1 ;;
esac
apt-get install -y --no-install-recommends /tmp/cartesi-rollups-node.deb
rm /tmp/cartesi-rollups-node.deb
mkdir -p /var/lib/cartesi-rollups-node/snapshots
Expand All @@ -238,7 +232,7 @@
COPY --from=nitro /usr/local/src/nitroctl /usr/local/bin/
COPY --from=tini /usr/local/bin/tini /usr/local/bin/
COPY --from=telegraf /usr/local/bin/telegraf /usr/local/bin/
COPY --from=sling-node --chmod=755 /usr/local/bin/cartesi-rollups-prt-node /usr/local/bin/cartesi-rollups-prt-node
COPY --from=sling-node --chmod=755 /usr/local/bin/cartesi-sling-node /usr/local/bin/cartesi-sling-node

COPY skel/ /
RUN <<EOF
Expand All @@ -251,7 +245,7 @@

################################################################################
# postgresql initdb
FROM ${POSTGRES_BASE_IMAGE} AS postgresql-initdb

Check warning on line 248 in packages/sdk/Dockerfile

View workflow job for this annotation

GitHub Actions / sdk / build

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG ${POSTGRES_BASE_IMAGE} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

ARG DEBIAN_FRONTEND=noninteractive
RUN <<EOF
Expand All @@ -264,7 +258,7 @@
COPY --from=rollups-runtime /usr/bin/cartesi-rollups-cli /usr/bin/
COPY --from=rollups-runtime /usr/lib/libcartesi* /usr/lib/

ARG POSTGRES_PASSWORD=password

Check warning on line 261 in packages/sdk/Dockerfile

View workflow job for this annotation

GitHub Actions / sdk / build

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "POSTGRES_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

# create rollupsdb databases
COPY <<EOF /docker-entrypoint-initdb.d/00-createdb.sql
Expand All @@ -284,12 +278,12 @@

################################################################################
# rollups-database image
FROM ${POSTGRES_BASE_IMAGE} AS rollups-database

Check warning on line 281 in packages/sdk/Dockerfile

View workflow job for this annotation

GitHub Actions / sdk / build

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG ${POSTGRES_BASE_IMAGE} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/
COPY --from=postgresql-initdb /var/lib/postgresql/data /var/lib/postgresql/data

################################################################################
# alto build
FROM node:${NODE_VERSION} AS alto

Check warning on line 286 in packages/sdk/Dockerfile

View workflow job for this annotation

GitHub Actions / sdk / build

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG node:${NODE_VERSION} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/
ARG ALTO_VERSION
ARG NODE_VERSION
ARG TARGETARCH
Expand All @@ -314,21 +308,19 @@
################################################################################
# linux kernel image stage
FROM scratch AS kernel-image
ARG CARTESI_IMAGE_KERNEL_VERSION
ARG CARTESI_LINUX_KERNEL_VERSION

ADD --checksum=sha256:5c900060da2db2bfa84cd39cd9cd722988c83c42225f3cac55f2d3157e48f32f \
https://github.com/cartesi/image-kernel/releases/download/v${CARTESI_IMAGE_KERNEL_VERSION}/linux-${CARTESI_LINUX_KERNEL_VERSION}.bin \
ADD --checksum=sha256:ad12ad141e639fb7b8ce0477dfbb7aa7a4d178222b06e0ce9b335a1c5230f0e1 \
https://github.com/cartesi/linux/releases/download/v${CARTESI_LINUX_KERNEL_VERSION}/linux-${CARTESI_LINUX_KERNEL_VERSION}.bin \
/usr/share/cartesi-machine/images/linux.bin

################################################################################
# linux headers stage
FROM base AS kernel-headers
ARG CARTESI_IMAGE_KERNEL_VERSION
ARG CARTESI_LINUX_KERNEL_VERSION

ADD --checksum=sha256:e3f140a8632fcfb18218e7aea32a7d002124d3dce5ba8121ae061ab7f40a6cf4 \
https://github.com/cartesi/image-kernel/releases/download/v${CARTESI_IMAGE_KERNEL_VERSION}/linux-headers-${CARTESI_LINUX_KERNEL_VERSION}.tar.xz \
ADD --checksum=sha256:0c6ef54c47e50502a00f6d3785be1f797f74c8bc2f0b3bc0f22bc26017569aa1 \
https://github.com/cartesi/linux/releases/download/v${CARTESI_LINUX_KERNEL_VERSION}/linux-headers-${CARTESI_LINUX_KERNEL_VERSION}.tar.xz \
/tmp/linux-headers-${CARTESI_LINUX_KERNEL_VERSION}.tar.xz
RUN tar -xJf "/tmp/linux-headers-${CARTESI_LINUX_KERNEL_VERSION}.tar.xz" -C /

Expand Down
7 changes: 3 additions & 4 deletions packages/sdk/docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ target "default" {
ALTO_VERSION = "1.2.7"
ALTO_PACKAGE_VERSION = "0.0.20"
CARTESI_BASE_IMAGE = "docker.io/library/debian:trixie-20260918@sha256:9cc080028c43b27d2074d63a5f9caf7166d731494965616c1a6d2827a004585c"
CARTESI_IMAGE_KERNEL_VERSION = "0.21.0"
CARTESI_LINUX_KERNEL_VERSION = "6.5.13-ctsi-2-v0.21.0"
CARTESI_MACHINE_EMULATOR_VERSION = "0.21.0"
CARTESI_LINUX_KERNEL_VERSION = "6.18.56-ctsi-1"
CARTESI_MACHINE_EMULATOR_VERSION = "0.22.0"
CARTESI_PASSKEY_SERVER_VERSION = "1.0.1"
CARTESI_PAYMASTER_VERSION = "0.2.0"
CARTESI_PRT_VERSION = "3.0.0-alpha.5"
CARTESI_PRT_VERSION = "3.0.0-alpha.6"
CARTESI_ROLLUPS_NODE_VERSION = "2.0.0-alpha.13"
FOUNDRY_VERSION = "1.5.1"
NITRO_VERSION = "c937fa4fd202074dd250086ebd92de6884968b84" # v0.8.1
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"version": "0.12.0-alpha.44",
"scripts": {
"build": "docker buildx bake --load --metadata-file=build.json"
"build": "docker buildx bake --load --metadata-file=build.json",
"fetch:rollups-node": "./scripts/fetch-rollups-node.sh"
}
}
39 changes: 39 additions & 0 deletions packages/sdk/scripts/fetch-rollups-node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Fetch the rollups-node .deb files built by cartesi/rollups-node CI, through
# nightly.link. WIP plumbing until the next rollups-node release.
set -euo pipefail

BRANCH="${ROLLUPS_NODE_BRANCH:-next/2.0}"
RUN_ID="${ROLLUPS_NODE_RUN_ID:-}"
BASE="https://nightly.link/cartesi/rollups-node"
DEST="$(cd "$(dirname "$0")/.." && pwd)/rollups-node"

sha256() {
if command -v sha256sum >/dev/null; then sha256sum "$@"; else shasum -a 256 "$@"; fi
}

if [[ -z "$RUN_ID" ]]; then
page="$BASE/workflows/build/${BRANCH//\//%2F}"
RUN_ID="$(curl -fsSL "$page" | grep -oE 'actions/runs/[0-9]+/artifacts\.zip' | head -n1 | grep -oE '[0-9]+' || true)"
[[ -n "$RUN_ID" ]] || { echo "no successful run found at $page" >&2; exit 1; }
fi

url="$BASE/actions/runs/$RUN_ID/artifacts.zip"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
curl -fsSL "$url" -o "$tmp/artifacts.zip"
unzip -q "$tmp/artifacts.zip" -d "$tmp/artifacts"

mkdir -p "$DEST"
rm -f "$DEST"/*.deb
for arch in amd64 arm64; do
src=("$tmp"/artifacts/cartesi-rollups-node-v*_"$arch".deb)
[[ -f "${src[0]}" ]] || { echo "missing $arch .deb in run $RUN_ID" >&2; exit 1; }
cp "${src[0]}" "$DEST/cartesi-rollups-node_$arch.deb"
done

{
echo "run: https://github.com/cartesi/rollups-node/actions/runs/$RUN_ID"
echo "url: $url"
(cd "$DEST" && sha256 cartesi-rollups-node_*.deb)
} | tee "$DEST/SOURCE"
Loading