diff --git a/.github/workflows/secure_release.yml b/.github/workflows/secure_release.yml new file mode 100644 index 0000000..8294193 --- /dev/null +++ b/.github/workflows/secure_release.yml @@ -0,0 +1,191 @@ +name: Secure Release & Publish Pipeline + +on: + pull_request: + branches: [ master ] + push: + tags: + - 'v*.*.*' + +permissions: + contents: write + pages: write + id-token: write + +jobs: + verify-integrity: + name: Source Integrity Verification + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build entlib-native + run: cargo build --release + + - name: Generate Source Archives + run: | + VERSION=$(git describe --tags --exact-match 2>/dev/null || echo "dev") + ARCHIVE_NAME="entlib-native-${VERSION}-source" + mkdir -p target/dist + git archive \ + --format=tar.gz \ + --prefix="${ARCHIVE_NAME}/" \ + -o "target/dist/${ARCHIVE_NAME}.tar.gz" \ + HEAD + git archive \ + --format=zip \ + --prefix="${ARCHIVE_NAME}/" \ + -o "target/dist/${ARCHIVE_NAME}.zip" \ + HEAD + cp ./public/public-key.asc target/dist/public-key.asc + echo "[+] Source archives generated" + ls -lh target/dist/ + + - name: Import Public Key (Trust Anchor) + run: gpg --import ./public/public-key.asc + + - name: Verify PGP Signature + run: | + echo "[*] Verifying PGP signature of RELEASE_HASHES.txt..." + gpg --verify ./public/RELEASE_HASHES.txt.asc ./public/RELEASE_HASHES.txt + echo "[+] PGP signature verification passed" + + create-release: + name: Create GitHub Release + if: startsWith(github.ref, 'refs/tags/v') + needs: verify-integrity + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build entlib-native + run: cargo build --release + + - name: Prepare Release Artifacts + env: + GITHUB_REF_NAME: ${{ github.ref_name }} + run: | + VERSION=$(git describe --tags --exact-match) + ARCHIVE_NAME="entlib-native-${VERSION}-source" + mkdir -p target/dist + git archive \ + --format=tar.gz \ + --prefix="${ARCHIVE_NAME}/" \ + -o "target/dist/${ARCHIVE_NAME}.tar.gz" \ + HEAD + git archive \ + --format=zip \ + --prefix="${ARCHIVE_NAME}/" \ + -o "target/dist/${ARCHIVE_NAME}.zip" \ + HEAD + cp ./public/public-key.asc target/dist/public-key.asc + cp ./public/RELEASE_HASHES.txt target/dist/RELEASE_HASHES.txt + cp ./public/RELEASE_HASHES.txt.asc target/dist/RELEASE_HASHES.txt.asc + + - name: Extract Tag Version + id: version + run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: "entlib-native ${{ steps.version.outputs.tag }}" + body: | + ## Source Distribution + + | File | Description | + |------|-------------| + | `entlib-native-${{ steps.version.outputs.tag }}-source.tar.gz` | Source archive (tar.gz) | + | `entlib-native-${{ steps.version.outputs.tag }}-source.zip` | Source archive (zip) | + | `RELEASE_HASHES.txt` | SHA3-512 + BLAKE3 checksums | + | `RELEASE_HASHES.txt.asc` | PGP detached signature | + | `public-key.asc` | PGP public key (Trust Anchor) | + + ## Verify Integrity + + ```bash + gpg --import public-key.asc + gpg --verify RELEASE_HASHES.txt.asc RELEASE_HASHES.txt + ``` + files: | + ./target/dist/entlib-native-*-source.tar.gz + ./target/dist/entlib-native-*-source.zip + ./target/dist/RELEASE_HASHES.txt + ./target/dist/RELEASE_HASHES.txt.asc + ./target/dist/public-key.asc + + publish-trust-anchor: + name: Publish Trust Anchor to GitHub Pages + if: startsWith(github.ref, 'refs/tags/v') + needs: create-release + runs-on: ubuntu-latest + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Extract Tag Version + id: version + run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" + + - name: Build Pages Site + env: + RELEASE_TAG: ${{ steps.version.outputs.tag }} + run: | + mkdir -p _site/keys "_site/releases/${RELEASE_TAG}" + + cp ./public/public-key.asc _site/keys/public-key.asc + + cp ./public/RELEASE_HASHES.txt \ + "_site/releases/${RELEASE_TAG}/RELEASE_HASHES.txt" + cp ./public/RELEASE_HASHES.txt.asc \ + "_site/releases/${RELEASE_TAG}/RELEASE_HASHES.txt.asc" + + cat > _site/index.html << 'PAGE' + + +
+ # 1. Import the public key
+ curl -sO https://quant-off.github.io/entlib-native/keys/public-key.asc
+ gpg --import public-key.asc
+
+ # 2. Download the release hashes and signature
+ VERSION="vX.Y.Z"
+ curl -sO "https://quant-off.github.io/entlib-native/releases/${VERSION}/RELEASE_HASHES.txt"
+ curl -sO "https://quant-off.github.io/entlib-native/releases/${VERSION}/RELEASE_HASHES.txt.asc"
+
+ # 3. Verify the signature
+ gpg --verify RELEASE_HASHES.txt.asc RELEASE_HASHES.txt
+
+
+
+ PAGE
+
+ - name: Upload Pages Artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: _site
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/cli/src/cmd/blake.rs b/cli/src/cmd/blake.rs
index 9d787a6..a9f504c 100644
--- a/cli/src/cmd/blake.rs
+++ b/cli/src/cmd/blake.rs
@@ -1,6 +1,7 @@
use super::hex_encode;
use crate::input;
use clap::Subcommand;
+use entlib_native_blake::file::{blake2b as blake2b_file, blake3 as blake3_file};
use entlib_native_blake::{Blake2b, Blake3};
#[derive(Subcommand)]
@@ -19,6 +20,32 @@ pub(crate) enum Ops {
#[arg(long)]
raw: bool,
},
+ /// BLAKE2b 파일 스트리밍 해시
+ #[command(name = "2b-file")]
+ Blake2bFile {
+ /// 출력 바이트 수 (1-64, 기본: 32)
+ #[arg(long, default_value_t = 32)]
+ output_len: usize,
+ /// 해시할 파일 경로
+ file: String,
+ #[arg(long)]
+ out_file: Option