소개
검증한 바이트가 실행 중인 릴리스가 되어야 검증된 전달물이 쓸모가 있습니다. Waymark에는 도보 축제 안내서를 변경하기 전에 승인되지 않은 묶음을 거부하는 재사용 가능한 수신 스크립트가 필요합니다.
짧은 셸 스크립트를 교체하고 거부 판단을 시험한 뒤 주최자가 요청한 업데이트를 발행합니다. 이 독립 환경은 원래 안내서와 자체 묶음으로 시작합니다. 앞 가이드 실습에서 서명, 독립적으로 신뢰하는 키, 요청된 메타데이터, 아카이브 다이제스트를 배웠습니다. 이제 Python 프로그래밍 없이 이를 결합합니다.
작동 중인 안내서와 수신 스크립트의 계약 이해하기
이 단계에서는 업데이트가 변경해야 할 것과 보존해야 할 것을 확인합니다. Event Guide를 연 뒤 Old Mill Walk를 여세요. 원래 event-guide 판은 2.0이며 집결 시각은 11:00입니다. All walks로 돌아가 경로표를 다운로드하세요. 업데이트 후에도 상세 페이지와 다운로드가 모두 작동해야 합니다.
안내서 홈 페이지는 제목 위에 판을 표시하고 각 산책 카드에 집결 시각을 보여 줍니다.

Workspace로 전환하세요. cd는 디렉터리를 변경하며 이 절대 경로는 어느 위치에서도 사용할 수 있습니다.
cd /home/labex/project/waymark
cat은 파일을 출력합니다. 독립적으로 제공된 업데이트 요청을 읽으세요.
cat /opt/labex-waymark/trust/request.json
요청은 제품 event-guide, 버전 2.1입니다. 승인된 업데이트는 Old Mill Walk의 집결 시각을 14:00로 옮깁니다. 다른 산책은 09:30으로 유지됩니다. 시작 스크립트를 읽으세요.
cat receive.sh
시작 스크립트는 묶음 자체에서 다이제스트를 가져와 발행 도구에 전달합니다. 다른 발행자도 서로 일치하는 매니페스트와 아카이브를 제공할 수 있습니다. 이 스크립트는 아직 서명이나 주최자가 요청한 제품/버전을 검증하지 않습니다. 발행하기 전에 교체해야 합니다.
필수 인터페이스는 다음과 같습니다.
bash receive.sh CANDIDATE_DIRECTORY DESTINATION_DIRECTORY
첫 인수는 공급업체 묶음 하나입니다. 두 번째는 안내서 발행 디렉터리이며 실제 프로젝트에서는 published입니다. 두 경로 모두 절대 또는 상대 경로일 수 있고, 이름이 바뀌거나 공백을 포함할 수 있습니다. 묶음 라벨이나 대상을 하드코딩하지 마세요. 업데이트 성공 시 0을 반환합니다. 거부 시 0이 아닌 값을 반환하고 기존 발행 파일을 모두 그대로 유지합니다. 정당한 업데이트는 이전 릴리스와 무관한 업로드를 보존합니다.
receive.sh를 편집하고 임시 파일을 만들 수 있습니다. 원본 묶음, 독립적인 키/요청, 준비된 발행 도구, 기타 런타임 파일은 변경하지 마세요. 수신 스크립트는 준비된 동일 도구와 독립적인 신뢰 파일을 사용할 수 있는 다른 디렉터리에 단독으로 복사해도 작동해야 합니다. 평가는 실제 안내서 검사와 함께 일회용 디렉터리에서도 이 계약을 시험합니다.
경로 철자가 틀리면 위의 절대 경로 cd를 실행하고 ls candidates로 라벨을 확인한 뒤 다시 실행하세요. 검사 실패 시 관련 증거를 살펴보아야 하며 환경을 초기화할 필요는 없습니다.
발행 전에 멈추는 수신 스크립트 설계하기
이 단계에서는 짧은 스크립트를 작성하기 전에 이해합니다. Workspace에 머무르세요.
수신 스크립트는 관련 파일 세 개를 전용 임시 디렉터리에 복사하고, 복사된 매니페스트를 검증하며, 제품/버전을 독립적인 요청과 비교하고, 복사된 아카이브와 서명된 다이제스트를 준비된 발행 도구에 전달합니다. 한 후보를 검증한 뒤 전달할 때 다른 후보 경로를 다시 여는 일은 하지 않습니다.
발행 도구 /opt/labex-waymark/publish.py는 준비된 아카이브 처리 코드입니다. 제공된 아카이브를 하나의 바이트 버퍼로 읽고, 그 버퍼를 제공된 다이제스트와 대조하며, site.json과 routes.csv만 안전하게 추출한 뒤 같은 바이트를 발행합니다. 이전 릴리스와 uploads/를 보존합니다. 누구의 서명을 신뢰할지, 주최자가 어떤 제품/버전을 요청했는지는 판단하지 않습니다. 그 판단은 수신 스크립트의 역할입니다.
다음 셸 기능을 사용합니다.
#!/bin/bash는 스크립트의 셸을 지정합니다.bash receive.sh로 실행해도 Bash를 명시적으로 선택합니다.set -euo pipefail은 처리되지 않은 명령 실패, 설정되지 않은 변수, 파이프라인 실패 시 스크립트를 중지합니다. 서명 실패 후에도 발행이 진행되어서는 안 됩니다.$1과$2는 두 인수입니다.candidate=$1은 값을 저장하고,"$candidate"는 공백을 포함해 하나의 인수로 확장합니다.$#은 인수 수이며[ "$#" -ne 2 ]는 그 수가 2가 아닌지 검사합니다.if,then,fi는 조건 블록의 경계입니다.$(command)는 명령 출력을 저장합니다.mktemp -d는 고유한 임시 디렉터리를 만듭니다.trap '...' EXIT는 스크립트가 끝날 때 정리 작업을 실행합니다. 여기서rm -rf -- "$stage"는 생성된 그 임시 디렉터리만 삭제합니다. 프로젝트 디렉터리로 바꾸지 마세요.--는 옵션 해석을 끝내 경로를 데이터로 취급하게 합니다.cp -- SOURCE SOURCE SOURCE DIRECTORY/는 세 파일을 복사합니다. 마지막 슬래시는 대상이 디렉터리임을 나타냅니다.jq -r .product FILE은 JSON 따옴표 없이 JSON 문자열을 읽습니다.jq -e는 결과가 거짓이면 실패 상태를 반환합니다.--arg product "$product"는 필터에$product라는 문자열 변수를 제공합니다.and는 모든 조건이 참이어야 함을 뜻합니다. 작은따옴표는 jq용 필터 텍스트를 보존합니다.> /dev/null은 출력된 불리언을 버리되 종료 상태는 유지합니다.echo ... >&2는 오류를 오류 스트림으로 쓰고,exit 2는 0이 아닌 상태로 종료합니다.
서명 명령은 앞 실습과 같은 독립적으로 고정된 공개 키를 사용합니다. --bundle은 복사된 서명 번들을 가리키고 마지막 인수는 복사된 매니페스트입니다. --insecure-ignore-tlog는 이 오프라인 합성 자료의 명시적 한계입니다. 고정된 키의 서명은 검사하지만 공개 로그 검증은 생략합니다. 이 수신 스크립트는 공개 신원이나 투명성 로그 검증기가 아닙니다.
마지막 Python 명령은 준비된 발행 도구를 호출합니다. 여러분이 Python을 작성하는 것은 아닙니다. 복사된 아카이브, 검증된 매니페스트의 다이제스트, 요청된 대상을 전달받습니다. 다이제스트와 아카이브 바이트가 다르면 기존 안내서에 손대기 전에 업데이트를 거부합니다.
재사용 가능한 수신 스크립트 저장하기
이 단계에서는 방금 살펴본 메커니즘으로 수신 스크립트를 작성합니다. Workspace의 /home/labex/project/waymark에서 시작하세요.
다음 명령은 receive.sh를 교체합니다. cat > receive.sh는 제공된 텍스트를 파일로 리디렉션합니다. <<'RECEIVER'는 here-document를 시작합니다. RECEIVER만 있는 줄까지의 모든 내용이 파일 내용이 됩니다. 이 표시를 따옴표로 감싸면 $1, $stage, jq 변수가 나중에 스크립트를 실행할 때까지 보존됩니다. 마지막 표시를 포함해 전체 블록을 붙여 넣으세요.
cat > receive.sh <<'RECEIVER'
#!/bin/bash
set -euo pipefail
if [ "$#" -ne 2 ]; then
echo "Usage: bash receive.sh CANDIDATE_DIRECTORY DESTINATION_DIRECTORY" >&2
exit 2
fi
candidate=$1
destination=$2
stage=$(mktemp -d)
trap 'rm -rf -- "$stage"' EXIT
cp -- "$candidate/manifest.json" "$candidate/manifest.sigstore.json" "$candidate/guide.tar.gz" "$stage/"
/opt/labex-waymark/bin/cosign verify-blob --key /opt/labex-waymark/trust/publisher.pub --bundle "$stage/manifest.sigstore.json" --insecure-ignore-tlog "$stage/manifest.json"
product=$(jq -r .product /opt/labex-waymark/trust/request.json)
version=$(jq -r .version /opt/labex-waymark/trust/request.json)
jq -e --arg product "$product" --arg version "$version" '.product == $product and .version == $version and .archive == "guide.tar.gz"' "$stage/manifest.json" > /dev/null
digest=$(jq -r .sha256 "$stage/manifest.json")
python3 /opt/labex-waymark/publish.py "$stage/guide.tar.gz" "$digest" "$destination"
RECEIVER
다시 읽어 보세요.
cat receive.sh
공개 키와 요청은 /opt/labex-waymark/trust/에서 가져오고, 매니페스트, 번들, 아카이브는 모두 "$stage"에서 가져오는지 확인하세요. 복사 후 원래 후보 디렉터리를 다시 읽지 않는다는 점에 주목하세요. 복사 후 공급업체 전달 디렉터리를 변경하거나 이름을 바꾸어도 발행 도구에 넘기는 바이트를 바꿀 수 없습니다.
마지막 표시를 빠뜨려 터미널에 계속 입력하라는 프롬프트가 나오면 한 줄에 RECEIVER만 입력하고 Enter를 누르세요. 파일을 잘못 붙여 넣었다면 here-document 전체를 반복하세요. 이 작업은 receive.sh만 교체합니다. 불완전한 수신 스크립트는 실행하지 마세요.
준비된 정책 검사는 스크립트를 변경하지 않고 일반 계정으로 일회용 발행 디렉터리에서 실행합니다. 실제 발행 파일, 거부 사례, 보존 동작을 검사하며 특정 명령 철자를 찾지는 않습니다.
sudo python3 /opt/labex-waymark/verify.py policy
이 준비된 검사가 격리된 일반 계정을 실행하려면 sudo가 필요하지만 수신 스크립트 자체에는 필요하지 않습니다. 검사는 실제 안내서를 건드리지 않습니다. 마지막 줄에서 요청된 서명된 안내서는 받아들이고 승인되지 않은 네 가지 사례는 거부함을 확인해야 합니다. 실패하면 보고된 판단을 살펴보고 receive.sh를 수정한 뒤 진행하세요.
실제 안내서를 업데이트하기 전에 거부 동작 관찰하기
이 단계에서는 원래 안내서를 계속 사용할 수 있는 상태에서 수신 스크립트가 세 가지 실패에 멈추는지 확인합니다. Workspace의 /home/labex/project/waymark에서 시작하세요.
먼저 다른 발행자가 서명한 묶음을 시도하세요. 서명 검증 오류와 0이 아닌 상태가 나와야 합니다.
bash receive.sh candidates/parcel-102 published
$?에는 바로 앞 명령의 종료 상태가 들어 있습니다. 다른 명령을 실행하기 전에 읽으세요.
echo $?
이제 진짜이지만 이전 판인 묶음을 시도하세요. 서명 검증은 통과하지만 요청된 제품/버전 비교가 거짓이므로 그 뒤 0이 아닌 상태가 나와야 합니다.
bash receive.sh candidates/parcel-101 published
echo $?
jq 비교는 의도적으로 출력을 내지 않습니다. 0이 아닌 상태가 거부를 기록합니다. 유효한 서명이 독립적인 요청보다 우선하지 않았습니다.
마지막으로 변경된 아카이브를 시도하세요. 서명은 통과하지만 발행 도구가 다이제스트 불일치를 보고하고 기존 안내서를 유지해야 합니다.
bash receive.sh candidates/parcel-103 published
echo $?
Event Guide로 전환해 새로 고치세요. 안내서 판은 여전히 2.0이고 Old Mill Walk는 11:00에 모여야 합니다. All walks로 돌아가 경로표를 다운로드하고 Visitor notice를 여세요. 모든 업데이트를 거부하는 수신 스크립트도 이전 안내서는 보존하므로, 정당한 업데이트가 성공하는지도 반드시 확인해야 합니다.
파일 누락이나 연결 오류는 이런 예상된 정책 거부와 다릅니다. 묶음 경로 철자가 틀리면 절대 작업 경로로 돌아가 candidates 목록을 확인한 뒤 다시 시도하세요. 웹사이트에 접근할 수 없다면 보고된 오류를 살펴보세요. 성공적인 거부라고 판단하지 마세요.
승인된 새 안내서 발행하고 사용하기
이 단계에서는 검증된 업데이트를 전달하고 실제 페이지와 다운로드를 사용합니다. Workspace의 /home/labex/project/waymark에서 시작하세요.
승인된 묶음을 수신하세요.
bash receive.sh candidates/parcel-104 published
Verified OK와 다음 출력이 나와야 합니다.
Published event-guide 2.1. Previous releases and uploads kept.
즉시 상태를 확인하세요.
echo $?
0이 나와야 합니다. Event Guide로 전환해 새로 고치세요. 홈 페이지는 이제 event-guide 판 2.1을 표시합니다. Old Mill Walk를 열고 14:00인지 확인한 뒤 All walks를 사용해 Riverside Welcome을 열고 09:30 집결이 유지되는지 확인하세요. All walks로 돌아가 새 경로표를 다운로드하세요. 두 행이 상세 페이지와 일치해야 합니다. Visitor notice를 열고 원래 안내가 남아 있는지 확인하세요.
승인된 홈 페이지는 판 2.1을 표시합니다. Old Mill Walk의 14:00 집결 시각을 보세요.

Workspace로 전환하세요. 실제 상태 자체 검사는 실행 중인 상세 페이지, 다운로드된 경로표 바이트, 현재 안내서 파일, 보존된 이전 릴리스와 공지를 읽습니다.
python3 /opt/labex-waymark/verify.py live
예상 출력:
The running guide and download match the approved release. Previous releases and visitor notice are preserved.
ls는 보존된 릴리스 디렉터리를 나열합니다.
ls published/releases
이전 event-guide-2.0-... 릴리스와 새 event-guide-2.1-... 릴리스가 있어야 합니다. 뒤의 문자들은 실제 아카이브 다이제스트에서 온 것으로 외울 값이 아닙니다.
실제 상태 검사가 실패하면 메시지를 통해 수신 판단 문제인지, 웹사이트 접근 불가나 원본 파일 변경인지 구분하세요. 필요하다면 수신 스크립트를 수정하고 원래 승인 묶음을 다시 수신하세요. 같은 유효한 업데이트를 반복해도 안전합니다. 발행 도구가 동일한 릴리스를 재사용하고 이전 파일을 보존합니다. 실제 상태 자체 검사를 반복해 결과를 확인하세요.
요약
전달물 자체를 신뢰하던 수신 스크립트를 독립적인 발행자 키와 주최자 요청을 확인하고, 서명된 아카이브 다이제스트를 실제 발행 바이트에 연결하는 스크립트로 교체했습니다. 잘못된 서명자, 진짜 이전 릴리스, 변경된 아카이브는 거부되었고 원래 서비스는 계속 사용할 수 있었습니다.
승인된 업데이트는 이제 상세 페이지와 일치하는 경로 다운로드가 작동하는 실제 안내서입니다. 챌린지에서는 같은 도구를 접근성 안내서에 적용하며, 잘못된 제품에 대한 진짜 서명된 묶음도 포함됩니다.


