diff --git a/.github/workflows/general_daily_security.yml b/.github/workflows/general_daily_security.yml index 39196e57..2b689c51 100644 --- a/.github/workflows/general_daily_security.yml +++ b/.github/workflows/general_daily_security.yml @@ -1,5 +1,6 @@ --- name: Security audit +permissions: {} on: schedule: @@ -8,9 +9,16 @@ on: jobs: audit: + name: Audit runs-on: ubuntu-latest + permissions: + contents: read + checks: write # rustsec/audit-check reports findings as a check run + issues: write # rustsec/audit-check opens/updates issues for new advisories steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - uses: actions-rs/audit-check@35b7b53b1e25b55642157ac01b4adceb5b9ebef3 # renovate: tag=v1.2.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr_cockpit.yml b/.github/workflows/pr_cockpit.yml deleted file mode 100644 index 5e582517..00000000 --- a/.github/workflows/pr_cockpit.yml +++ /dev/null @@ -1,171 +0,0 @@ ---- -name: Pull Request Cockpit - -on: - pull_request: - paths: - - ".github/workflows/pr_cockpit.yml" - - "rust/stackable-cockpitd/**" - - "rust/stackable-cockpit/**" - - "docs/modules/ROOT/**" - - "Cargo.lock" - - "deploy/**" - - "docker/**" - - "go.sum" - -env: - RUST_VERSION: 1.95.0 - GO_VERSION: '^1.26.0' - CARGO_TERM_COLOR: always - CARGO_INCREMENTAL: "0" - CARGO_PROFILE_DEV_DEBUG: "0" - RUSTFLAGS: "-D warnings" - RUSTDOCFLAGS: "-D warnings" - RUST_LOG: "info" - DEV_REPO_HELM_URL: https://repo.stackable.tech/repository/helm-dev - -jobs: - general-checks: - name: General Pull Request Checks - uses: ./.github/workflows/pr_general.yml - - check-charts: - name: Helm Chart Check - runs-on: ubuntu-latest - needs: - - general-checks - steps: - - name: Checkout Repository - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - - name: Setup Helm - uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 - with: - version: v3.6.2 - - - name: Setup Rust - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - - - name: Setup Rust Cache - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - with: - key: pr-stackable-cockpit-chart - - - name: Regenerate Charts - run: make regenerate-charts - - - name: Checking that Helm Charts are up-to-date - run: git diff --exit-code - - - name: Helm Charts not up-to-date - if: ${{ failure() }} - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - core.setFailed('Committed Helm charts were not up to date, please regenerate and re-commit!') - - publish: - name: Publish ${{ matrix.runner.arch }} Image - permissions: - id-token: write - runs-on: ${{ matrix.runner.name }} - strategy: - matrix: - runner: - - {name: "ubuntu-latest", arch: "amd64"} - - {name: "ubicloud-standard-8-arm", arch: "arm64"} - env: - NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} - OCI_REGISTRY_SDP_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_GITHUB_ACTION_BUILD_SECRET }} - OCI_REGISTRY_SDP_USERNAME: "robot$sdp+github-action-build" - OCI_REGISTRY_SDP_CHARTS_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_CHARTS_GITHUB_ACTION_BUILD_SECRET }} - OCI_REGISTRY_SDP_CHARTS_USERNAME: "robot$sdp-charts+github-action-build" - outputs: - IMAGE_TAG: ${{ steps.printtag.outputs.IMAGE_TAG }} - needs: - - check-charts - steps: - - name: Checkout Repository - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # tag=v25 - - - name: Setup Rust - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Install cosign - uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1 - - - name: Install syft - uses: anchore/sbom-action/download-syft@9246b90769f852b3a8921f330c59e0b3f439d6e9 # v0.20.1 - - - name: Setup Rust Cache - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - with: - key: pr-stackable-cockpit-chart - - - name: Update Version - run: | - cargo install --locked cargo-edit --version 0.11.11 - cargo set-version --offline --package stackable-cockpit 0.0.0-pr${{ github.event.pull_request.number }} - - # Recreate charts and publish charts and docker image. The "-e" is needed as we want to override the - # default value in the makefile if called from this action, but not otherwise (i.e. when called locally). - # This is needed for the HELM_REPO variable. - - name: Build Docker Image and Helm Chart - run: make -e build - - name: Publish Docker Image and Helm Chart - if: ${{ !github.event.pull_request.head.repo.fork }} - run: make -e publish - - id: printtag - if: ${{ !github.event.pull_request.head.repo.fork }} - name: Output Image Name and Tag - run: echo "IMAGE_TAG=$(make -e print-docker-tag)" >> "$GITHUB_OUTPUT" - - create_manifest_list: - name: Build and publish manifest list - needs: - - publish - runs-on: ubuntu-latest - permissions: - id-token: write - env: - NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} - OCI_REGISTRY_SDP_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_GITHUB_ACTION_BUILD_SECRET }} - OCI_REGISTRY_SDP_USERNAME: "robot$sdp+github-action-build" - OCI_REGISTRY_SDP_CHARTS_PASSWORD: ${{ secrets.HARBOR_ROBOT_SDP_CHARTS_GITHUB_ACTION_BUILD_SECRET }} - OCI_REGISTRY_SDP_CHARTS_USERNAME: "robot$sdp-charts+github-action-build" - steps: - - name: Install cosign - uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1 - - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - submodules: recursive - # This step checks if the current run was triggered by a push to a pr (or a pr being created). - # If this is the case it changes the version of this project in all Cargo.toml files to include the suffix - # "-pr" so that the published artifacts can be linked to this PR. - - uses: stackabletech/cargo-install-action@main - with: - crate: cargo-edit - bin: cargo-set-version - - name: Update version if PR - if: ${{ github.event_name == 'pull_request' }} - run: cargo set-version --offline --package stackable-cockpit 0.0.0-pr${{ github.event.pull_request.number }} - - name: Build manifest list - run: | - # Creating manifest list - make -e docker-manifest-list-build - # Pushing and signing manifest list - make -e docker-manifest-list-publish diff --git a/.github/workflows/pr_docs.yml b/.github/workflows/pr_docs.yml deleted file mode 100644 index 0c307065..00000000 --- a/.github/workflows/pr_docs.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Pull Request Docs - -on: - pull_request: - paths: - - ".github/workflows/pr_docs.yml" - - "docs/**" - -jobs: - general-checks: - name: General Pull Request Checks - uses: ./.github/workflows/pr_general.yml diff --git a/.github/workflows/pr_general.yml b/.github/workflows/pr_general.yml deleted file mode 100644 index 9939cffc..00000000 --- a/.github/workflows/pr_general.yml +++ /dev/null @@ -1,115 +0,0 @@ ---- -name: Pull Request General - -on: workflow_call - -env: - RUST_VERSION: 1.95.0 - GO_VERSION: '^1.26.0' - CARGO_TERM_COLOR: always - CARGO_INCREMENTAL: "0" - CARGO_PROFILE_DEV_DEBUG: "0" - RUSTFLAGS: "-D warnings" - RUSTDOCFLAGS: "-D warnings" - RUST_LOG: "info" - -jobs: - run_udeps: - name: Run Cargo Udeps - runs-on: ubuntu-latest - env: - RUSTC_BOOTSTRAP: 1 - steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - with: - key: udeps - cache-all-crates: "true" - - run: cargo install --locked cargo-udeps@0.1.55 - - run: cargo udeps --workspace - - run_cargodeny: - name: Run Cargo Deny - runs-on: ubuntu-latest - strategy: - matrix: - checks: - - advisories - - bans licenses sources - # Prevent sudden announcement of a new advisory from failing ci: - continue-on-error: ${{ matrix.checks == 'advisories' }} - steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979 # v2.0.15 - with: - command: check ${{ matrix.checks }} - - run_rustdoc: - name: Run RustDoc - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - components: rustfmt - - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - with: - key: doc - - - run: cargo doc --document-private-items - - run_tests: - name: Run Cargo Tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - with: - submodules: recursive - - - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 - with: - key: test - - - run: cargo test - - tests_passed: - name: All tests passed - needs: - - run_udeps - - run_cargodeny - - run_rustdoc - - run_tests - runs-on: ubuntu-latest - steps: - - name: log - run: echo All tests have passed! diff --git a/.github/workflows/pr_pre-commit.yml b/.github/workflows/pr_prek.yaml similarity index 64% rename from .github/workflows/pr_pre-commit.yml rename to .github/workflows/pr_prek.yaml index 581c8056..20720ae9 100644 --- a/.github/workflows/pr_pre-commit.yml +++ b/.github/workflows/pr_prek.yaml @@ -1,10 +1,12 @@ --- -name: pre-commit +name: prek on: pull_request: merge_group: +permissions: {} + env: CARGO_TERM_COLOR: always RUST_TOOLCHAIN_VERSION: "nightly-2025-05-26" @@ -12,13 +14,14 @@ env: NIX_VERSION: "2.25.2" jobs: - pre-commit: + prek: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false fetch-depth: 0 - - uses: stackabletech/actions/run-pre-commit@5901c3b1455488820c4be367531e07c3c3e82538 # v0.4.0 + - uses: stackabletech/actions/run-prek@0fe048f952bee522474903a925ea48dc706a0bb4 # v0.17.5 with: rust: ${{ env.RUST_TOOLCHAIN_VERSION }} hadolint: ${{ env.HADOLINT_VERSION }} diff --git a/.github/workflows/pr_stackablectl.yml b/.github/workflows/pr_stackablectl.yml index faa33072..04c74154 100644 --- a/.github/workflows/pr_stackablectl.yml +++ b/.github/workflows/pr_stackablectl.yml @@ -1,5 +1,6 @@ --- name: Pull Request Stackablectl +permissions: {} on: pull_request: @@ -24,15 +25,38 @@ env: RUST_LOG: "info" jobs: - general-checks: - name: General Pull Request Checks - uses: ./.github/workflows/pr_general.yml + cargo-udeps: + name: Run cargo-udeps + runs-on: ubuntu-latest + env: + RUSTC_BOOTSTRAP: 1 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + submodules: recursive + + - name: Setup Rust + run: | + rustup toolchain install "$RUST_VERSION" --profile minimal + rustup default "$RUST_VERSION" + + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 + with: + key: udeps + cache-all-crates: "true" + - run: cargo install --locked cargo-udeps@0.1.55 + - run: cargo udeps --workspace build: name: Build stackablectl for ${{ matrix.target }} runs-on: ${{ matrix.os }} needs: - - general-checks + - cargo-udeps strategy: fail-fast: false matrix: @@ -56,16 +80,20 @@ jobs: os: macos-latest steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false submodules: recursive - - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 - with: - toolchain: ${{ env.RUST_VERSION }} - targets: ${{ matrix.target }} + - name: Setup Rust + env: + TARGET: ${{ matrix.target }} + run: | + rustup toolchain install "$RUST_VERSION" --profile minimal + rustup target add "$TARGET" --toolchain "$RUST_VERSION" + rustup default "$RUST_VERSION" - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ env.GO_VERSION }} @@ -75,16 +103,6 @@ jobs: - name: Build for non-Windows if: matrix.os != 'windows-latest' - run: cargo build --target ${{ matrix.target }} -p stackablectl - - - name: Ensure shell completions up-to-date - if: matrix.os == 'x86_64-unknown-linux-gnu' - run: | - cargo xtask gen-comp - git diff --exit-code - - - name: Ensure man page is up-to-date - if: matrix.os == 'x86_64-unknown-linux-gnu' - run: | - cargo xtask gen-man - git diff --exit-code + env: + TARGET: ${{ matrix.target }} + run: cargo build --target "$TARGET" -p stackablectl diff --git a/.github/workflows/release_stackablectl.yml b/.github/workflows/release_stackablectl.yml index cdb899b3..999e9828 100644 --- a/.github/workflows/release_stackablectl.yml +++ b/.github/workflows/release_stackablectl.yml @@ -1,5 +1,6 @@ --- name: Stackablectl Release Pipeline +permissions: {} on: push: @@ -15,11 +16,33 @@ env: RUSTFLAGS: "-D warnings" RUSTDOCFLAGS: "-D warnings" RUST_LOG: "info" + RELEASE_TAG: ${{ github.ref_name }} jobs: + create-release: + name: Create Draft Release + runs-on: ubuntu-latest + permissions: + contents: write # required to draft the release + steps: + # This checkout is only here so that a .git directory is present because the gh CLI needs it. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Create Draft Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release create --draft --verify-tag "$RELEASE_TAG" + release: name: Release for ${{ matrix.target }} runs-on: ${{ matrix.os }} + needs: + - create-release + permissions: + contents: write # required to upload release binaries and SBOM assets to the GitHub Release strategy: fail-fast: false matrix: @@ -38,38 +61,65 @@ jobs: file-suffix: "" steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false submodules: recursive - - uses: dtolnay/rust-toolchain@0e66bd3e6b38ec0ad5312288c83e47c143e6b09e # v1 + - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1 with: toolchain: ${{ env.RUST_VERSION }} targets: ${{ matrix.target }} - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '^1.22.2' + go-version: '^1.26.0' - name: Install cargo-cyclonedx - run: cargo install --locked cargo-cyclonedx@${{ env.CARGO_CYCLONEDX_VERSION }} + run: cargo install --locked cargo-cyclonedx@"$CARGO_CYCLONEDX_VERSION" - name: Build Binary if: matrix.os != 'windows-latest' - run: cargo build --target ${{ matrix.target }} --release --package stackablectl + env: + TARGET: ${{ matrix.target }} + run: cargo build --target "$TARGET" --release --package stackablectl - name: Generate SBOM run: cargo cyclonedx --all --spec-version 1.5 --describe binaries - name: Rename Binary - run: mv target/${{ matrix.target }}/release/stackablectl${{ matrix.file-suffix }} stackablectl-${{ matrix.target }}${{ matrix.file-suffix }} + env: + TARGET: ${{ matrix.target }} + FILE_SUFFIX: ${{ matrix.file-suffix }} + run: mv "target/$TARGET/release/stackablectl$FILE_SUFFIX" "stackablectl-$TARGET$FILE_SUFFIX" - name: Rename SBOM - run: mv rust/stackablectl/stackablectl_bin.cdx.xml stackablectl-${{ matrix.target }}.cdx.xml + env: + TARGET: ${{ matrix.target }} + run: mv rust/stackablectl/stackablectl_bin.cdx.xml "stackablectl-$TARGET.cdx.xml" - name: Upload Release Binary and SBOM - uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TARGET: ${{ matrix.target }} + FILE_SUFFIX: ${{ matrix.file-suffix }} + run: gh release upload "$RELEASE_TAG" "stackablectl-$TARGET$FILE_SUFFIX" "stackablectl-$TARGET.cdx.xml" + + finish-release: + name: Finish Release + needs: + - release + runs-on: ubuntu-latest + permissions: + contents: write # required to finalize the release + steps: + # This checkout is only here so that a .git directory is present because the gh CLI needs it. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - files: | - stackablectl-${{ matrix.target }}${{ matrix.file-suffix }} - stackablectl-${{ matrix.target }}.cdx.xml + persist-credentials: false + + - name: Finish Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release edit --draft=false --latest "$RELEASE_TAG" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 62bd2bf5..1feac396 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,12 @@ repos: args: ["--allow-missing-credentials"] - id: detect-private-key + - repo: https://github.com/EmbarkStudios/cargo-deny + rev: 1c9ca2b643ee15722178c1350501aabb024dd6f3 # 0.19.9 + hooks: + - id: cargo-deny + args: ["--all-features", "check", "advisories", "bans", "licenses", "sources"] + - repo: https://github.com/doublify/pre-commit-rust rev: eeee35a89e69d5772bdee97db1a6a898467b686e # 1.0 hooks: @@ -93,6 +99,22 @@ repos: stages: [pre-commit, pre-merge-commit, manual] pass_filenames: false + - id: cargo-doc + name: cargo-doc + language: system + entry: cargo doc --no-deps --document-private-items + stages: [pre-commit, pre-merge-commit] + pass_filenames: false + files: \.rs$|Cargo\.(toml|lock) + + - id: cargo-test + name: cargo-test + language: system + entry: cargo test + stages: [pre-commit, pre-merge-commit] + pass_filenames: false + files: \.rs$|Cargo\.(toml|lock) + - id: cargo-rustfmt name: cargo-rustfmt files: \.rs$ diff --git a/Cargo.lock b/Cargo.lock index 59c83046..207f72aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1321,9 +1321,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +checksum = "a9f37a958b41b3b19ee2707c06439c0e9e547e847223eb791ecb0cb821c65e27" dependencies = [ "atomic-waker", "bytes", diff --git a/Cargo.nix b/Cargo.nix index d95e9b30..1986049c 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -4106,9 +4106,9 @@ rec { }; "h2" = rec { crateName = "h2"; - version = "0.4.15"; + version = "0.4.16"; edition = "2021"; - sha256 = "0mgilh1g8gydcchqi6acs5l6j0gwg5jwpa64sj4b3ncb9v497c3c"; + sha256 = "09syqqhvh36b3rwyn8vjhiz597hfki1hcz3hwagb3cs1ifapmwx9"; authors = [ "Carl Lerche " "Sean McArthur "