不动手也能回答,动了就要还原
한국어 원문으로 표시합니다.
목표
고객 운영 서버에 대한 다섯 가지 질문에 읽기 전용 수단만으로 답한다. 그다음 디렉터리 상태를 지문으로 굳히고 견주는 도구를 만들어, 꼭 바꿔야 하는 설정 한 줄을 바꾸고 확인하고 실제로 되돌려 스냅샷과 내용이 다른 파일이 0개임을 증명한다.
왜 중요한가
조사 중에 무언가를 바꾸면 그 뒤로 보이는 값이 원래 값인지 우리가 만든 값인지 알 수 없게 된다. 고객이 그 사이에 본 지표도 오염되고, "언제부터 이렇게 됐죠" 라는 질문에 우리가 답의 일부가 된다. 작은 변경일수록 되돌리는 것을 잊는다. 그리고 되돌렸다고 믿는 것과 되돌렸다는 것이 증명되는 것은 다르다. "원래대로 했습니다" 는 검증할 수 없는 문장이고, "되돌린 뒤 스냅샷과 견주었더니 내용이 다른 파일이 0개입니다" 는 확인할 수 있는 문장이다. 그보다 먼저 물을 것은 정말 바꿔야 답이 나오는가다. 많은 경우 같은 질문에 읽기 전용으로 답하는 길이 있다. 읽기 전용인지 아닌지를 스스로 속이지 않는 방법은 쓴 명령을 기록하는 것이다. 이 실습은 고객 승인을 받아 반영하는 변경 작업과 다르다. 그 앞 단계 — 조사 중에 손이 미끄러지는 순간에 대한 첫 주의 규율이다. 채점기는 여러분이 적어 낸 문구를 믿지 않는다. 다섯 답은 채점기가 직접 다시 재고, 스냅샷 도구에는 파일을 더하고 지우고 내용을 바꾸고 권한만 바꾸고 시각만 바꾼 자리를 만들어 다섯 가지를 갈라내는지 본다.
단계
- /root/readonly/gen_site.py 를 만들어 실행해 /root/readonly/site/ 를 만드세요. 설정·주문 원장 240행·로그 180줄·조회기가 들어갑니다.
- 읽기 전용 수단만으로 다섯 질문에 답해 /root/readonly/answers.json 에 적으세요. 답마다 쓴 명령을 함께 남깁니다.
- /root/readonly/snapshot.py 를 만들어 디렉터리를 훑어 파일마다 지문·크기·권한·수정 시각을 담고, 지금 상태를 /root/readonly/baseline.json 에 굳히세요.
--baseline <스냅샷>을 더해 견준 결과를 내게 하세요. added·removed·changed·mtime_only·same 다섯으로 가릅니다.- 설정의 max_retry 를 3에서 5로 바꾸고, 무엇을 왜 바꾸는지와 되돌리는 명령을 /root/readonly/change.json 에 적으세요.
- 조회기로 바꾼 효과를 확인해 /root/readonly/verify.json 에 적으세요.
- 되돌리고, 스냅샷과 견준 결과를 /root/readonly/revert_diff.json 에 남기세요. 내용이 다른 파일이 0개여야 합니다.
- /root/readonly/readonly_report.md 에 네 절로 적으세요.
참고
- 답할 다섯 질문의 id 는
app_version·pending_orders·log_errors·backoff_ms·oldest_pending_days입니다. 차례대로 설정의 버전, 원장에서 status 가 pending 인 주문 수, 로그에서 ERROR 가 든 줄 수, 설정의 backoff_ms, 가장 오래된 pending 주문이 2026-09-17 기준 며칠 됐는지입니다. - 답 파일:
{"answers": [{"id", "value", "how"}]}. value 는 숫자면 숫자로, 문자열이면 문자열로 적습니다. how 에는 실제로 쓴 명령을 그대로 적습니다 — 읽기 전용이 아닌 명령이 섞여 있으면 채점기가 잡습니다. - 스냅샷 실행 계약:
python3 /root/readonly/snapshot.py --dir <디렉터리> --out <스냅샷 JSON>은 한 줄 요약을 표준출력에 내고 0 으로 끝납니다. 디렉터리가 없으면 3 입니다. - 스냅샷 JSON:
{"root", "taken_at", "files": {상대경로: {"sha256", "bytes", "mode", "mtime"}}}. mode 는 8진수 세 자리 문자열(644), mtime 은 초 단위 정수입니다. 심볼릭 링크와 디렉터리는 담지 않습니다. - 견주기 실행 계약:
python3 /root/readonly/snapshot.py --dir <디렉터리> --baseline <스냅샷> --out <차이 JSON>. - 차이 JSON:
{"added": [경로...], "removed": [경로...], "changed": [{"path", "fields": [...]}], "mtime_only": [경로...], "same": 정수}. changed 의 fields 는 sha256·bytes·mode 중 달라진 것만 오름차순으로 담습니다. 내용과 크기와 권한이 같고 시각만 다르면 changed 가 아니라 mtime_only 입니다. - 변경 기록:
{"target_file", "key", "before", "after", "sha256_before", "sha256_after", "why", "approved_by", "baseline", "apply", "rollback"}. sha256 두 개는 바꾸기 전과 후의 대상 파일 지문이고, rollback 에는 원래 값이 들어 있어야 합니다. - 확인 기록:
{"question", "command", "before", "after", "confirmed"}. 조회기는python3 /root/readonly/site/bin/report.py --q retry_budget [--conf <설정>]으로 부르고, 재시도 예산은 max_retry 의 두 배입니다. - 흔한 실수: 스냅샷을 바꾼 뒤에 뜨기, 되돌리는 명령을 바꾼 뒤에 적기(원래 값이 흐려집니다), 수정 시각 차이를 숨기려고 시각까지 맞추기, 한 번에 두 가지를 바꾸기.
- 조회기 report.py 가 고객 서버에 이미 있다는 설정과 max_retry 를 5로 올린다는 값은 이 실습의 가정입니다.
- 참고 문서: 파이썬 hashlib 문서와 os 문서가 지문과 파일 정보를, POSIX 의 sys/stat.h가 수정 시각과 권한 비트의 뜻을, POSIX 의 touch가 시각을 손대는 방법을 설명합니다.
운영 서버를 손에 쥐기
/root/readonly/gen_site.py 를 만들어 실행해 /root/readonly/site/ 를 만드세요. etc/app.conf, data/app.db(orders 240행), var/log/app.log(180줄), bin/report.py 가 들어갑니다.
조회기 report.py 는 고객 서버에 이미 있는 도구라고 생각하세요. 우리가 만든 것이 아니라 거기 있던 것이고, 우리는 그것을 돌려 볼 수만 있습니다. 만든 뒤 조회기를 한 번 돌려 무엇을 물을 수 있는지 보세요.
읽기만으로 답하기
/root/readonly/answers.json 에 다섯 질문의 답을 적으세요. id 는 app_version·pending_orders·log_errors·backoff_ms·oldest_pending_days 이고, 답마다 실제로 쓴 명령을 how 에 남깁니다.
설정은 열어 읽고, 원장은 읽기 전용으로 열어 세고, 로그는 줄을 세면 됩니다. 이미 있는 조회기를 쓰는 것도 읽기입니다. how 에 적은 명령에 쓰기가 섞여 있으면 채점기가 잡으므로, 적으면서 스스로 확인하세요.
바꾸기 전 상태를 굳히기
/root/readonly/snapshot.py 를 만들어 --dir --out 으로 디렉터리를 훑고, /root/readonly/baseline.json 에 지금의 site 상태를 굳히세요. 파일마다 sha256·bytes·mode·mtime 을 담습니다.
굳혀 두지 않으면 나중에 되돌렸다는 것을 증명할 것이 없습니다. 경로는 --dir 을 기준으로 한 상대 경로로 담고, 디렉터리와 심볼릭 링크는 담지 않습니다. mode 는 권한 세 자리만, mtime 은 초 단위 정수로 적으세요.
견주는 기능 더하기
--baseline <스냅샷> 을 더해 견준 결과를 내게 하세요. added·removed·changed·mtime_only·same 다섯으로 가르고, changed 에는 달라진 항목 이름만 fields 에 담습니다.
내용과 크기와 권한이 같고 수정 시각만 다른 경우를 changed 에 넣으면, 되돌린 뒤 결과가 늘 빨강이 되어 아무 정보도 주지 못합니다. 그 경우를 따로 세는 것이 이 도구의 핵심입니다. 채점기는 다섯 경우를 모두 만들어 넣습니다.
한 건만, 되돌릴 준비를 하고
설정의 max_retry 를 3에서 5로 바꾸고 /root/readonly/change.json 에 target_file·key·before·after·sha256_before·sha256_after·why·approved_by·baseline·apply·rollback 을 적으세요. rollback 에는 원래 값이 들어 있어야 합니다.
되돌리는 명령은 바꾸기 전에 적으세요. 바꾼 뒤에 적으려 하면 원래 값을 기억에 의존하게 되고, 3이었는지 30이었는지는 30분 뒤에 놀랍도록 흐려집니다. 승인도 한 줄로 남기세요 — 없으면 나중에 그 변경은 우리가 몰래 한 것이 됩니다.
의도한 효과가 났는지 값으로 보기
조회기로 바꾼 효과를 확인해 /root/readonly/verify.json 에 question·command·before·after·confirmed 를 적으세요. question 은 retry_budget 이고, before 와 after 는 바꾸기 전과 후의 조회기 출력입니다.
바꿨다는 사실과 바꾼 것이 의도한 효과를 냈다는 사실은 다릅니다. 조회기는 --conf 로 다른 설정 파일을 줄 수 있으니, 바꾸기 전 값을 담은 임시 설정으로 한 번 돌려 before 를 얻을 수 있습니다. 출력은 그대로 문자열로 적으세요.
되돌리고 증명하기
change.json 의 rollback 대로 되돌린 뒤, 스냅샷과 견준 결과를 /root/readonly/revert_diff.json 에 남기세요. added·removed 가 비어 있고 changed 가 0개여야 합니다. 수정 시각만 다른 파일은 mtime_only 에 남습니다.
되돌렸다고 믿는 것과 되돌렸다는 것이 증명되는 것은 다릅니다. 견준 결과가 증명입니다. 수정 시각 차이를 숨기려고 시각까지 맞추지 마세요 — 그때부터는 우리가 흔적을 지운 것이 됩니다.
무엇을 만졌고 무엇을 되돌렸는지 적기
/root/readonly/readonly_report.md 에 ## 읽기만으로 답한 것 ## 꼭 바꿔야 했던 한 건 ## 바꾼 뒤 무엇을 확인했나 ## 되돌린 증거 네 절로 적으세요. 다섯 질문의 id, 바꾼 키와 값, 조회기 출력의 변화, 견준 결과의 숫자가 모두 나와야 합니다.
보고서는 손으로 쓰지 말고 answers·change·verify·revert_diff 네 파일에서 만들어 내세요. 마지막 절에는 남은 자국(수정 시각만 다른 파일)도 그대로 적으세요 — 숨기면 그때부터 우리가 흔적을 지운 것이 됩니다.