20 הדקות האחרונות
הצ'קליסט
Section titled “הצ'קליסט”-
git pull --ff-onlyבכל repo לפני הדחיפה האחרונה (ה-CI כותב ל-gitops) - אין שאריות: TODO / FIXME /
exit 1של stub /<PLACEHOLDER>/repoURL: ""/defaultImageTag: "" - אין token, סיסמה או מפתח ב-Git: לא בעץ ולא בהיסטוריה
- אין רווח בסוף שורה ואין CRLF
- כל branch וכל tag נדחפו;
git statusנקי בכל repo - סולם האימות ירוק, והפלט נשמר ב-
evidence/ - כל deliverable קיים ולא ריק (לא תבנית, לא
...) - הרצף האידמפוטנטי עבר, ואתה קראת את הפלט של ההרצה השנייה
- המצב הסופי של ה-cluster הוא מה שהחוזה דורש (ראה בהמשך)
סקריפט אחד שמריץ את הבדיקות הסטטיות
Section titled “סקריפט אחד שמריץ את הבדיקות הסטטיות”מריצים בתוך כל repo (source, ci, gitops, templates). קורא בלבד, ולא מדפיס ערכי secrets: בדיקות ה-token מדפיסות שמות קבצים בלבד.
#!/usr/bin/env bash# finish-check.sh — run inside each repo clone before the final push. Read-only.set -uDELIVERABLES="${DELIVERABLES:-}" # space-separated paths, e.g. "evidence/ladder.txt DECISIONS.md"bad=0hit() { echo "FAIL $1"; bad=1; }ok() { echo "PASS $1"; }
if git grep -nIE 'TODO|FIXME|CHANGEME|repoURL: ""|defaultImageTag: ""' -- . ':!*.md' ':!*/versions/*'; then hit "leftovers above"; else ok "no leftovers"; fiif git grep -lIE '(glpat|gldt|glrt|glrtr|glcbt|glptt|glft|glagent|gloas)-[0-9A-Za-z_-]{8,}|-----BEGIN [A-Z ]*PRIVATE KEY' -- .; then hit "token/key text in files above"; else ok "no token/key text in tracked files"; fiif [ -n "$(git log --all -G'(glpat|gldt|glrt|glcbt)-[0-9A-Za-z_-]{8,}|-----BEGIN [A-Z ]*PRIVATE KEY' --format=%h -- .)" ]; then hit "token/key text in history"; else ok "no token/key text in history"; fiif git ls-files . | grep -E '(^|/)(\.env|token|username|password|id_[a-z0-9]+|[^/]+\.(pem|key))$'; then echo "WARN secret-like file names tracked (above): open each, confirm no secret"; else ok "no secret-like file names tracked"; fiif git grep -nIE ' +$' -- . ':!*.md'; then hit "trailing whitespace above"; else ok "no trailing whitespace"; fiif git grep -lI $'\r' -- . ; then hit "CRLF in files above"; else ok "no CRLF"; fifor f in $DELIVERABLES; do [ -s "$f" ] && ok "deliverable $f" || hit "deliverable missing or empty: $f"; done[ -z "$(git status --porcelain)" ] && ok "working tree clean" || hit "uncommitted changes"if git rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1; then [ -z "$(git log '@{u}..HEAD' --oneline)" ] && ok "nothing unpushed" || hit "unpushed commits"else hit "no upstream set"; fiexit "$bad"cd <DIR>DELIVERABLES="evidence/ladder.txt DECISIONS.md" bash finish-check.shecho "exit=$?"איך מוודאים: הכול PASS ו-exit=0. כל FAIL מדפיס מעליו את השורות הרלוונטיות. git grep רואה קבצים tracked בלבד; קובץ חדש בלי git add נתפס בבדיקת git status. הסקריפט נבדק ב-repo מבודד: נקי נתן exit=0; עם token מושתל, repoURL: "" ו-deliverable חסר נתן exit=1.
שאריות: TODO, placeholder, stub
Section titled “שאריות: TODO, placeholder, stub”git grep -nIE 'TODO|FIXME|CHANGEME' -- . ':!*.md'git grep -nIE 'repoURL: ""|defaultImageTag: ""|imageRepository: ""' -- .git grep -nIE 'TODO.*exit 1' -- .git grep -nIE '<[A-Z][A-Z0-9_]+>' -- '*.yaml' '*.yml' '*.sh' '*.json'הדפוס TODO.*exit 1 תופס stub (echo "TODO …"; exit 1). exit 1 לבד לא נכנס ל-grep: בסקריפטים אמיתיים הוא תקין (command -v openssl || exit 1), וב-TRIDENT הוא נותן כ-20 פגיעות לגיטימיות שמסתירות את הבעיה.
איך מוודאים: פלט ריק. פגיעה ב-<…> בתוך הערת # היא תיעוד ולא placeholder: קרא את השורה לפני שמוחקים. versions/<ENV>.yaml עם defaultImageTag: "" תקין עד שהוקדם ל-env, ולכן הוא מוחרג בסקריפט.
Secrets ב-Git: עץ והיסטוריה
Section titled “Secrets ב-Git: עץ והיסטוריה”לכל token ב-GitLab יש prefix קבוע. הטבלה לקוחה מתיעוד GitLab (Token overview, נבדק 2026-10-04):
| prefix | סוג |
|---|---|
glpat- | personal / project / group access token |
gldt- | deploy token |
glrt-, glrtr- | runner authentication token |
glcbt- | CI/CD job token |
glptt-, glft-, glagent-, gloas- | trigger, feed, agent for Kubernetes, OAuth application secret |
glsoat- | SCIM token, לא token של service account |
Token של service account לא מופיע בטבלה בנפרד; אם נוצר כ-PAT הוא יתחיל ב-glpat-. ה-regex מכסה את הקבוצה כולה.
# 1. working tree (file names only, never the secret line)git grep -lIE '(glpat|gldt|glrt|glrtr|glcbt|glptt|glft|glagent|gloas)-[0-9A-Za-z_-]{8,}' -- .git grep -lIE -e '-----BEGIN [A-Z ]*PRIVATE KEY' -- .# 2. assignments with a literal value (a variable name is fine, a string is not)git grep -nIiE '(password|passwd|pwd|token)["'"'"']?[[:space:]]*[:=][[:space:]]*["'"'"']?[A-Za-z0-9+/=_.-]{8,}' -- . | grep -vE '[:=] *["'"'"']?[$<]'# 3. secret-like file names trackedgit ls-files . | grep -E '(^|/)(\.env|token|username|password|id_[a-z0-9]+|[^/]+\.(pem|key))$'# 4. history: commits that ever added or removed such text (hashes only)git log --all --format='%h %s' -G'(glpat|gldt|glrt|glcbt)-[0-9A-Za-z_-]{8,}|-----BEGIN [A-Z ]*PRIVATE KEY' -- .# 5. the log -p form, printing a COUNT and not the linesgit log --all -p -- . | grep -cE '^\+.*(glpat|gldt|glrt|glcbt)-[0-9A-Za-z_-]{8,}'איך מוודאים: שלבים 1, 2 ו-4 ריקים; שלב 5 מחזיר 0. פגיעה בשלב 3 אינה בהכרח בעיה: פתח את הקובץ והחלט.
הרצה על תיקיית TRIDENT (קריאה בלבד) לבדיקת false positives: שלבים 1 ו-5 נתנו אפס. שלב 2 נתן שתי שורות, שתיהן שם משתנה (password=DB_PASSWORD) ולא ערך. שלב 3 הציג source/.env (קובץ הגדרות של Compose, בלי secret). שלב 4 הראה commits ישנים של הקורס עם קבצי tls/*.key של ה-lab (חומר לא-production שנמחק מהעץ): בדיוק מה שבדיקת עץ בלבד מפספסת.
אותו עיקרון לפלט: לא מדביקים ל-scrollback פקודה שמדפיסה token (cat של קובץ credential, kubectl get secret -o yaml). בודקים קיום וגודל: [ -s <FILE> ], wc -c < <FILE>.
רצף האידמפוטנטיות
Section titled “רצף האידמפוטנטיות”bash verify.sh && bash cleanup.sh && bash verify-clean.sh && bash cleanup.sh && bash verify-clean.shecho "exit=$?"איך מוודאים: exit=0, וקראת את הפלט של cleanup.sh השני (על cluster נקי, חייב להצליח בלי exit 1 על "לא נמצא"). verify.sh: PASSED הוא לא סוף: ההרצה השנייה היא מה שנבדק. סדר הניקוי, finalizers וסקריפט מלא: verify/cleanup ו-bash/templates.
Deliverables
Section titled “Deliverables”for f in <FILE> <FILE>; do [ -s "$f" ] && echo "ok $f" || echo "MISSING $f"; donefind evidence -type f -size -20cאיך מוודאים: אין MISSING, והפקודה השנייה ריקה. קובץ קטן מ-20 בתים הוא כמעט בוודאי ... או תבנית ריקה (כך נראו 5 מתוך 6 קבצי ראיות בהגשה אמיתית בקורס). קובץ answers/DECISIONS שעדיין מכיל את התבנית המקורית שווה לריק.
ראיות (evidence)
Section titled “ראיות (evidence)”קובץ ראיה הוא פלט אמיתי של פקודה, עם תאריך, שנשמר לפני ה-cleanup. פקודה קרא-בלבד לכל שלב בסולם:
mkdir -p evidence{ date -u +%FT%TZ; kubectl -n argocd get applications; } > evidence/argo-apps.txtkubectl -n argocd get applications -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.sync.status}{"/"}{.status.health.status}{"\n"}{end}' > evidence/argo-status.txt[ -s evidence/argo-status.txt ] && cat evidence/argo-status.txtאיך מוודאים: כל הקבצים לא ריקים, וכל Application Synced/Healthy. גרסה עם before/after: creativity.
סולם אימות סופי
Section titled “סולם אימות סופי”מריצים את verify/overview מלמעלה למטה ועוצרים בראשון שאדום: render, pipeline, Argo, objects, /info, תכונות GitOps, נתונים שורדים. Synced/Healthy לבד לא מספיק: צריך גם version = candidate ב-/info של כל env, ו-accepted שעולה בין שתי קריאות.
איך מוודאים: כל השלבים ירוקים ושמורים ב-evidence/. בדיקה שלילית אחת (פעולה אסורה שנכשלת, למשל kubectl auth can-i שמחזיר no) שווה יותר מעוד בדיקה חיובית.
הדחיפה האחרונה
Section titled “הדחיפה האחרונה”git pull --ff-onlygit push origin --allgit push origin --tagsgit ls-remote --heads --tags origingit for-each-ref --format='%(refname:short) %(upstream:short) %(upstream:track)' refs/headsאיך מוודאים: ls-remote מציג כל branch וכל tag שצריך (למשל v1.0.0); בפקודה האחרונה אין [ahead …]. branch בלי upstream מוצג ריק: ודא ב-ls-remote שהוא קיים.