마스킹과 보존 기간
무엇이 아예 저장되지 않고, 무엇이 저장되기를 멈추는가. 마스킹은 쓰기 전에 실행됩니다. 나중에 지운 비밀 값은 이미 한 번 기록된 것이기 때문입니다.
마스킹은 저장 전에 실행됩니다
프롬프트와 응답은 mcpd가 가지고 있는 것 중 가장 값어치 있는 동시에 가장 위험한 것입니다. 마스킹은 수집 파이프라인의 세 번째 단계로 쓰기보다 앞에 있으므로, 규칙에 걸린 값은 데이터베이스에 아예 닿지 않습니다.
-
Decode
OTLP or native, gzip or plain
-
Sample
Decided once, at the root
-
Redact
Before anything is written
-
Price
From the configured price book
-
Store
One transaction per batch
Redaction is stage three, not a cleanup job. A value that a rule matches never reaches storage at all.
순서가 전부입니다. 사후에 지운 값은 이미 디스크에도, 미리 쓰기 로그에도, 어쩌면 어젯밤 백업에도 있었습니다. 아예 쓰지 않았다는 것은 나중에 지웠다는 것과 다른 보장이고, 묻는 사람에게 분명하게 말할 수 있는 것은 앞의 하나뿐입니다.
마스킹은 기본으로 켜져 있습니다. 설정한 뒤에야 보호해 주는 도구는 아무도
보호하지 못합니다. --no-redact, 또는
MCPD_NO_REDACT가 이것을 끄는데, 상류에서 이미 마스킹하고 있을
때에만 합리적인 선택입니다.
마스킹은 이 선의 데몬 쪽 끝입니다. 반대쪽 끝은 SDK가 쥐고 있습니다.
MCPD_CAPTURE_PAYLOADS=false, 또는 코드에서
capture_payloads를 쓰면 프롬프트와 응답이 프로세스 안에 남습니다.
스팬은 시간, 상태, 사용량, 모델, 상관 정보, 오류를 그대로 달고 도착하지만
input과 output은 큐에 들어가기 전에 버려지므로 결코
네트워크를 건너지 않습니다. 바이트 자체를 보내면 안 되는 팀은 이것을
설정하고, 민감한 내용이 없는 스팬은 자기만 다시 켤 수 있습니다.
기본 규칙
규칙은 소문자 부분 문자열의 집합과 모드 하나로 이루어집니다. 키 이름을
소문자로 바꾼 값이 그중 하나라도 포함하면 규칙에 걸립니다. 부분 문자열로
대조하기 때문에 X-API-Key, authorization,
customer_email이 대소문자와 접두사를 하나하나 적어 두지 않아도
모두 걸립니다.
| 모드 | 걸리는 키 이름 |
|---|---|
mask | api_key, apikey, api-key,
secret, password, passwd,
access_token, refresh_token,
id_token, bearer,
authorization, auth_token,
private_key, client_secret,
session_token, credential,
signature, x-api-key |
partial | email, phone, ssn,
credit_card, card_number, iban |
hash | user_id, userid |
걸린 키가 객체나 배열을 담고 있으면 그 아래의 모든 것도 함께 마스킹됩니다.
{"credential": {"value": "hunter2", "note": "prod"}}는
이름이 위험해 보이는 쪽만이 아니라 두 필드를 모두 잃습니다.
한계는 분명히 말해 둘 만합니다. 규칙은 값이 아니라 키 이름에
걸립니다. 사용자가 프롬프트 한가운데에 붙여 넣어 content라는
키에 저장된 API 키는 여기 있는 어떤 규칙에도 걸리지 않습니다. 마스킹은
구조화된 형태의 자격 증명과 식별자 수집을 막습니다. 내용 검사기가 아니며,
그렇게 여기면 실망하게 됩니다.
네 가지 모드
| 모드 | 값에 일어나는 일 |
|---|---|
drop | 키가 통째로 사라집니다. 애초에 보내지 않은 것과 같습니다. |
mask | 값이 [redacted]로 바뀝니다. |
partial |
앞의 두 글자와 뒤의 두 글자만 남고 가운데는 말줄임표로 이어집니다.
alice@example.com은 al…om이 됩니다. 이미
알고 있는 값을 알아볼 수 있을 만큼이되, 쓸 수는 없을 만큼입니다. 여섯
글자 이하인 값은 대신 전체가 마스킹됩니다. 다섯 글자 중 넷을 남기면
대부분을 드러내는 셈이기 때문입니다.
|
hash |
값이 sha256:과, 키를 사용한 SHA-256 다이제스트의 앞 12
바이트를 16진수 24자로 적은 값으로 바뀝니다.
|
기본 규칙은 넷 중 셋을 씁니다. 기본값으로 버려지는 것은 없습니다.
drop은 필드가 있다는 사실조차 남기고 싶지 않을 때, 직접 추가하는
규칙을 위해 있습니다.
$ curl -s "$MCPD/v1/api/traces/$TRACE" | jq .spans[0].input{ "question": "Where is my order A-1042?", "api_key": "[redacted]", "email": "al…om", "user_id": "sha256:9f2c1b7d4a08e5c3f6b1d0a4"} 해시에 키를 쓰는 이유
해시는 필드를 쓸모 있는 상태로 남겨 둡니다. 같은 키 아래에서는 같은 입력이 같은 다이제스트를 내므로, 마스킹된 사용자 id로 여전히 묶을 수 있고, 어떤 실패를 겪은 사람이 몇 명인지 셀 수 있으며, 그중 한 사람을 세션 너머까지 따라갈 수 있습니다. 그 사람이 누구인지는 가지고 있지 않은 채로 말입니다.
키가 없으면 그 성질이 구멍이 됩니다. 식별자는 좁고 추측하기 쉬운 공간에서 나오므로, 다이제스트와 이 소스를 가진 사람이면 누구나 하나가 맞을 때까지 후보를 해시해 볼 수 있습니다. 다이제스트를 단지 번거로운 것이 아니라 복원할 수 없는 것으로 만들어 주는 것이 바로 키입니다.
내장 키는 소스에 있는 상수이므로 공개된 값입니다. 무엇이든 해시하는 배포라면 자기 키를 설정하십시오.
해시하고 만료시키는 배포
mcpd --redact-key "$MCPD_REDACT_KEY" --retention-days 30 키를 교체하면 연결이 의도적으로 끊어집니다. 모든 다이제스트가 바뀌므로 교체 이전에 쓴 행은 이후에 쓴 행과 더 이상 이어 붙일 수 없습니다. 그것이 교체의 목적이자 교체의 대가입니다. 습관처럼 일정에 맞춰서가 아니라, 연결을 끊고 싶을 때 교체하십시오.
교체하기 전에 그 대가의 나머지 절반을 읽어 두십시오. 개인 단위 삭제는 저장된 다이제스트를 대조하므로, 새 키가 적용되는 순간부터 이전 키로 쓴 모든 행은 삭제 요청이 닿지 못하는 곳에 놓입니다. 어느 키가 어느 행을 썼는지 아무것도 기록하지 않기 때문에, mcpd는 이런 일이 벌어졌다고 알려 줄 수 없습니다. 할 수 있는 일은 그 결과로 나온 0이 답인 척 지나가게 두지 않는 것뿐이며, 아래의 0에 관한 절이 바로 그 거부입니다.
스팬만이 아니라 모든 시그널
비밀 값은 프롬프트를 통해서만큼이나 로그 한 줄을 통해서도 쉽게 새어 나가므로, 같은 마스킹기가 들어오는 길에 여섯 시그널 모두를 훑습니다.
- 스팬:
input,output,attributes,metadata. - 로그: 구조화된
fields. - 메트릭:
labels. - 점수:
metadata. - 피드백:
metadata, 그리고 자유 텍스트comment. - 관점 노트: 문장 자체인
text.
스팬의 이름과 로그 레코드의 메시지는 마스킹기를 거치지 않습니다. 이들은 페이로드가 아니라 식별자이고, 고쳐 쓰면 묶음이 깨집니다. 고객의 이메일 주소로 스팬 이름을 만들지 마십시오.
실행 저장소는 마스킹되지 않습니다
지속성 실행은 예외이며, 의도한 것입니다. 실행 저장소는 실행의 입력, 상태, 출력,
상관 정보와, 모든 단계의 입력, 출력, 오류를 보낸 그대로 보관하고,
user_id도 해시하지 않습니다. 이들은 워크플로의 작업 상태입니다. 뒤의
단계가 이것을 다시 읽으며, 마스킹기가 고쳐 쓴 값은 실행이 하는 일을 바꿀
것입니다. 실행이 트레이스 저장소에 쓰는 스팬은 보통의 수집 경로를 거치므로,
트레이스 저장소는 그것들을 다른 모든 스팬처럼 마스킹되고 해시된 채로 가집니다.
아래 절들이 말하듯 보존 기간과 삭제 요청은 둘 다 실행 저장소에 닿고, API를 통한
실행의 모든 읽기는 감사 로그에 기록됩니다.
긴 문자열과 깊은 문서
규칙에 걸렸든 걸리지 않았든, 모든 것에 두 가지 한도가 적용됩니다.
128 KiB보다 긴 문자열은 잘리고, 값이 짧은 것이 아니라 잘린 것임을 읽는 사람이
알 수 있도록 … [N bytes truncated]가 뒤에 붙습니다. 자르는
지점은 문자 경계이며, 여러 바이트로 된 코드포인트 안쪽은 절대 아닙니다. 폭주한
프롬프트 하나가 데이터베이스의 크기를 정해서는 안 됩니다.
순회는 깊이 32에서 멈추고, 그 아래는 [too deeply nested]로
바뀝니다. 열려 있는 수집 포트에 도착한 병적이거나 자기 자신을 참조하는 문서가
CPU를 붙잡아 둘 수 없습니다.
보존 기간
--retention-days, 또는 MCPD_RETENTION_DAYS는 지정한
일수보다 오래된 시그널을 지웁니다. 이것을 빼면 아무것도 지워지지 않습니다.
기본적으로 데이터를 남기는 쪽이 옳은 방향입니다. 지난달 트레이스를 조용히
버리는 도구는 하필 가장 나쁜 순간에 그 사실이 드러납니다.
이 정리는 조회 시점이 아니라 데몬 안에서 한 시간마다 도는 타이머로 실행됩니다.
보존 기간 정리는 아주 많은 행을 지울 수 있고, 그 작업이 누군가의 요청 안에
들어가서는 결코 안 됩니다. 한 번의 정리는 하나의 트랜잭션으로,
received_at이 기준 시점보다 오래된 스팬, 로그, 메트릭, 트레이스
행과, 자기 타임스탬프가 그런 점수, 피드백, 관점 노트를 지운 다음, 몇
행이 사라졌는지 로그에 남깁니다. 전문 검색 색인 항목은 그것을 가리키는 행이 아직
남아 있는 동안 먼저 정리되므로, 미아가 되는 것이 없습니다.
같은 정리가 같은 기간으로 실행 저장소도 정리합니다. 루트가 기준 시점보다 먼저 끝난 모든 지속성 실행을 그 자식 실행과, 그것들에 대해 저장된 모든 것과 함께 지웁니다. 정리하는 동안 워커가 붙잡혀 있지 않도록 배치 단위로 지웁니다. 끝나지 않은 실행은 아무리 오래 기다리고 있었어도 결코 지워지지 않습니다. 정의는 정리하지 않습니다.
정리는 --project가 지정한 프로젝트와, 설정 파일의
projects 블록에 있는 모든 프로젝트를 대상으로 하며, 기본
프로젝트만 보는 것이 아닙니다. 거기에서 자기 retention_days를
정한 프로젝트는 그 값으로, 나머지는 데몬의 값으로 정리됩니다. 어느 쪽에도 없는
프로젝트, 즉 보내는 쪽이 임의로 이름 붙인 프로젝트는 기간이 없어 전혀 정리되지
않습니다. 하나의 데몬이 여러 팀을 담당할 때 이것이 중요합니다. 30일만
보관하기로 한 팀이 다른 팀의 설정만 정리에 반영되는 바람에 조용히 30일을 넘겨
보관하는 일이 없고, 아무도 적어 두지 않은 팀은 전부를 보관합니다.
한 사람에 대한 삭제 요청
DELETE /v1/api/subjects/{user_id}는 한 사람에 대한 요청을 한
번의 호출로 처리합니다. 식별자는 계측이 설정한 그대로 보내십시오. 데몬은
수집할 때 적용한 것과 같은 해시를 적용하므로, user_id를 해시하는
배포에서도 먼저 해시할 필요가 없습니다.
삭제의 단위는 행이 아니라 실행입니다. 보통 user_id를 달고 있는
것은 루트 스팬뿐이고 프롬프트와 응답을 담고 있는 것은 자식 스팬이므로, 그
사람을 지목한 행만 지우면 페이로드가 남습니다. 어떤 실행은 그 트레이스 요약이
그 사람을 지목하거나 스팬 중 하나라도 지목하면 대상이 되고, 그때는 실행 전체가
사라집니다.
- 그 실행의 모든 스팬과, 스팬이 담고 있던 입력과 출력.
- 거기에 딸린 로그, 메트릭, 점수, 피드백, 관점 노트.
-
span_id는 지목하면서trace_id는 지목하지 않는 시그널. 그 사람의 실행 중 한 단계에 붙어 있는 점수나 로그 한 줄은, 대상 실행의 트레이스 id뿐 아니라 스팬 id를 통해서도 찾아냅니다. -
붙을 실행 없이 그 사람 앞으로 기록된 로그 줄. 자기 자신의
user_id로 대조합니다. -
그 사람이 쓴 피드백. 어디에 붙어 있든
author_id로 대조합니다. 그 행에는 그 사람이 직접 쓴 글이 담겨 있고, 다른 사람의 실행에 붙어 있을 수도 있는데 예전에는 그런 것이 살아남곤 했습니다. - 대상 실행에서 담아 둔 데이터셋 케이스. 이들은 삭제되지 않고 비워집니다. 다음다음 절에서 그 이유를 설명합니다.
-
지속성 실행을 처리하는 데몬에서는, 상관 정보에 그
user_id를 담고 있는 끝난 모든 실행과, 그 자식 실행의 트리 전체와, 실행 저장소가 그것들에 대해 들고 있는 모든 것. 실행 저장소는user_id를 해시하지 않고 보관하므로, 실행을 시작할 때 준 값 그대로 대조합니다. 그 사람의 실행 가운데 끝나지 않은 것은 건드리지 않습니다. 그것을 지우면 그 실행이 속한 워크플로가 망가지기 때문입니다. 그런 실행은runs_in_flight에 세고note에 이름을 밝히므로, 취소하거나 끝나게 둔 다음 요청을 다시 보낼 수 있습니다.
실행 저장소를 먼저 지웁니다. 실행의 스팬은 트레이스 저장소에 쓰일 때까지 그 실행의 아웃박스에서 기다리므로, 실행을 먼저 지우면 아직 기다리는 스팬이 지워지고, 그다음 트레이스 저장소의 삭제가 이미 쓰인 스팬을 지웁니다.
응답이 담는 것
시그널별 건수, 실행 저장소에 대한 두 건수, 그리고 그 옆에서 건수만으로는 말할 수
없는 것을 담는 여섯 개의 필드입니다. 무엇을 일부러 남겼는지, 그리고 작은 숫자를
이 사람에 관해 여기에 저장된 것은 없다는 뜻으로 읽어도 되는지입니다.
deleted는 여섯 시그널 건수의 합입니다. 실행 건수와
aspect_notes_erased는 그 옆에 따로 보고되며, 거기에 더해지지
않습니다.
$ curl -sX DELETE "$MCPD/v1/api/subjects/u_8841?project=checkout" | jq{ "project": "checkout", "traces": 1, "spans": 2, "logs": 1, "metrics": 0, "scores": 1, "feedback": 1, "deleted": 6, "runs_erased": 1, "runs_in_flight": 0, "dataset_items_erased": 1, "aspect_notes_erased": 0, "datasets": [ "checkout-regressions" ], "deletes_pending": false, "unmatchable_identifiers": 0, "note": "1 captured dataset cases were emptied in place rather than deleted, so a regression test is not destroyed without anyone being told. They hold no payload any more."} | 필드 | 알려 주는 것 |
|---|---|
runs_erased |
실행 저장소에서 지운 지속성 실행의 수. 자식 실행을 포함합니다.
deleted에는 세지 않습니다. 데몬이 실행을 처리하지 않으면
이 필드가 없습니다
|
runs_in_flight |
끝나지 않아서 손대지 않고 남긴 그 사람의 지속성 실행의 수. 취소할
실행은 note가 밝힙니다. 데몬이 실행을 처리하지 않으면 이
필드가 없습니다
|
dataset_items_erased |
자리에서 비워진 케이스의 수. 행 자체는 그대로 남아 있으므로
deleted에는 세지 않습니다
|
aspect_notes_erased |
지운 관점 노트의 수. 그 위에 찍힌 여섯 시그널 건수의 합인
deleted에는 세지 않습니다
|
datasets | 그 케이스들이 어느 데이터셋에 있는지. 가서 볼 수 있도록 |
deletes_pending | 백엔드가 응답한 뒤에 삭제를 적용하는 경우 참. 그때 건수는 이미 디스크를 떠난 것이 아니라 대조에 걸린 것을 뜻합니다 |
unmatchable_identifiers | 이 프로젝트에 저장된 식별자 가운데, 이 요청이 대조할 수 없는 형태였던 것의 수 |
note | 위의 숫자가 답의 전부가 아닐 수 있는 이유. 전부일 때는 이 필드가 없습니다 |
담아 둔 케이스는 삭제되지 않고 비워집니다
운영 환경에서 담아 둔 데이터셋 케이스는 입력을 그대로 복사해 가지고 있으므로, 실행만 지우고 사본을 남기면 그 사람의 말이 데이터셋에 남습니다. 그렇다고 케이스를 통째로 지우는 것은 다른 종류의 피해입니다. 누군가는 버그가 다시 나타나지 않게 하려고 그 실행을 담아 두었고, 그 사람의 회귀 테스트를 말 한마디 없이 부수는 것은 mcpd가 스스로 내릴 결정이 아닙니다.
그래서 페이로드만 덮어쓰고 행은 살려 둡니다. 케이스의 입력과 메타데이터가 있던
자리는 {"erased": true}로 읽히고, 원본 실행으로 돌아가는
연결은 지워지며, 응답이 케이스가 몇 개였고 어느 데이터셋이었는지 알려 줍니다.
케이스는 눈에 보이게 비어 있고, 이는 운영자가 조치할 수 있는 상태입니다.
아예 손이 닿지 않는 케이스가 하나 있는데, 이유는 테넌시입니다. 다른 프로젝트에 속한 데이터셋에 담긴 케이스는 비워지지도 않고 세어지지도 않습니다. 이 호출은 한 프로젝트에 대해 인가되고 한 프로젝트만 건드립니다. 그 경계를 넘어가는 삭제는 읽을 수 없는 데이터셋에 무엇이 들어 있는지 알아내는 수단이 될 것입니다. 그 프로젝트에 닿는 키로, 그 프로젝트에서도 그 사람을 삭제하십시오.
이 요청이 하지 않는 일
한 프로젝트만 건드립니다. ?project=가 그것을 지정하고, 빼면
데몬의 기본 프로젝트가 쓰입니다. 그 프로젝트에 닿지 못하는 키는 403으로
거부되고 아무것도 지워지지 않습니다. 키가 열 수 없는 프로젝트에 있는 같은
사람의 행은 건드리지도 세지도 않으므로, 건수가 그 사람이 다른 곳에 존재한다는
사실을 드러낼 수 없습니다. 여러 프로젝트에서 한 사람을 지우는 일은 각각에 닿는
키로 프로젝트마다 한 번씩 호출하는 일입니다.
저장된 것이 없는 사람에 대해서는 404가 아니라 0이 담긴 200이 돌아옵니다. 요청한 상태는 이미 성립해 있고, 404는 아무도 물을 자격이 없는 물음, 즉 그 사람이 이 키가 볼 수 있는 어딘가에 존재하는지에 답해 버릴 것입니다. 시간 초과 뒤에 다시 호출해도 안전한 이유도 이것입니다. 두 번째 호출은 오류가 아니라 두 번째 정리의 더 작은 건수를 보고합니다.
이것은 시스템 전체에서 한 사람을 지우는 수단이 아닙니다. mcpd는 mcpd가 저장한 것을 지웁니다. 다른 OTLP 엔드포인트로 전달한 것은 거기에서도 지워야 하고, mcpd는 그것이 어떻게 되었는지 알지 못합니다.
키, 그리고 그 기록
삭제는 키가 설정되어 있을 때 admin 키를 요구하고, admin 키가 설정되지 않았으면
read 키로 폴백하므로 기존 배포는 가지고 있던 범위를 유지합니다. 삭제는 동작,
프로젝트, 요청한 키의 다이제스트와 함께 감사 로그에 기록되고, 거부된 시도도
같은 방식으로 기록됩니다. user_id를 해시하는 곳에서는 행이
지목하는 값도 다이제스트입니다. 감사 로그는 자기가 설명하는 데이터보다 오래
남으므로, 원본 식별자를 거기에 쓰면 그 사람이 지워 달라고 한 이름을 보존 기간
정리가 훑지 않는 테이블에 남겨 두게 됩니다.
한 번에 한 실행씩 지우는 방법도 그대로 있습니다.
DELETE /v1/api/traces/{trace_id}는 실행 하나와 거기에 딸린
모든 것을 하나의 트랜잭션으로 지우고, 지운 행의 수를 돌려줍니다.
삭제가 돌려준 0은 의심해야 할 값입니다
0은 운영자가 어떤 사람에게 그 사람에 관해 가진 것이 없다고 그대로 옮기는 값이고, 이 엔드포인트가 증명할 수 없는 유일한 숫자이기도 합니다. 저장된 식별자는 마스킹 키로 해시되어 있고 어느 키가 어느 행을 해시했는지 아무것도 기록하지 않으므로, 0은 그 행들이 쓰인 뒤에 키가 바뀌었다는 뜻일 수도 있습니다. mcpd는 둘을 구분하지 못합니다. 할 수 있는 일은 앞의 0처럼 읽히는 맨 0을 결코 돌려주지 않는 것입니다.
아래는 실행이 기록된 뒤에 마스킹 키가 교체된 상태에서, 같은 사람을 삭제한 경우입니다. 건수는 모두 0이고 행은 그대로 있습니다.
$ curl -sX DELETE "$MCPD/v1/api/subjects/u_8841?project=checkout" | jq "{deleted, unmatchable_identifiers, note}"{ "deleted": 0, "unmatchable_identifiers": 0, "note": "Nothing matched. Stored identifiers are hashed with the redaction key, so this means no stored identifier hashes to this subject under the key in force now. It does not mean nothing about this person was ever stored: rows written under a different redaction key cannot be matched by this endpoint."} 노트가 증명할 수 있는 것은 프로젝트에 따라 다릅니다. 이 프로젝트의 어떤 것도 누구에게 귀속되어 있지 않으면 키 변경이 감출 만한 행이 없고, 노트도 정확히 그렇게 말합니다. 그렇지 않으면 0은 증명되지 않은 것입니다. 그 행들이 쓰인 마스킹 키를 복원해서 요청을 다시 보내십시오.
거부하지 않고 알려 주는 쪽을 택했고, 이는 의도적인 절충입니다. 거부하면 시간 초과 뒤의 재요청이 깨질 것이고, 본 적 없다는 응답과 한 시간 전에 지웠다는 응답이 서로 달라져 이 엔드포인트가 어떤 사람이 어떤 프로젝트에 알려져 있는지 묻는 수단이 될 것이며, 마스킹 설정을 한 번이라도 바꾼 배포에서는 올바르게 아무것도 대조하지 못한 경우까지 포함해 모든 삭제가 막힐 것입니다.
이 요청이 대조할 수 없었던 식별자
키 교체는 보이지 않습니다. 하지만 식별자를 해시할지 말지 자체를 바꾼
것은 보이며, mcpd가 볼 수 있는 것이 바로
unmatchable_identifiers입니다. 해시된 식별자는
sha256: 접두사로 알아볼 수 있으므로, 저장소는 자기가 가진 식별자
가운데 이 요청이 들고 온 것과 반대 형태인 것이 몇 개인지 셉니다. 해시된 요청에
대한 평문 행이거나, 그 반대입니다. 그 행들은 다른 마스킹 설정에서 쓰인
것이고, 그 사람의 것일 수 있으며, 이 요청은 그것들을 지목할 수 없습니다.
이 계산은 0일 때만이 아니라 모든 삭제에서 실행되며, 아래 응답이 그 이유입니다.
이 프로젝트는 마스킹을 켠 채로 쓰였다가, 다시 끈 채로 쓰였습니다. 요청은 나중에
쓰인 행을 대조해 지웠고, 더 오래된 두 식별자는 해시되어 있어 이 요청이 애초에
지목할 수 없었습니다. deleted에서 멈춘 건수였다면 완전한 답처럼
읽혔을 것입니다.
$ curl -sX DELETE "$MCPD/v1/api/subjects/u_8841?project=checkout" | jq "{deleted, unmatchable_identifiers, note}"{ "deleted": 2, "unmatchable_identifiers": 2, "note": "2 stored identifiers in this project are in a form this request could not match, so rows written under a different redaction setting were not searched and rows about this person may remain. Restore the redaction setting those rows were written under and repeat the request."} 이 수는 그 사람 자신의 행이 아니라 프로젝트가 가진 모든 식별자를 대상으로 세므로, 그 둘은 전혀 다른 사람의 것일 수도 있습니다. 이것이 말할 수 있는 전부입니다. 대신 성공한 것처럼 보이는 삭제를 완전한 삭제로 읽는 일만은 막아 줍니다.
보장은 세 백엔드에서 서로 같지 않습니다
SQLite와 Postgres는 응답을 만든 그 트랜잭션 안에서 지웁니다. 응답이 도착할 때
행은 이미 사라져 있고, deletes_pending은 false입니다.
ClickHouse는 그렇지 않습니다. 거기에서 삭제는 비동기 뮤테이션입니다. 서버가
구문을 받아들이고 백그라운드에서 적용하므로, 응답은 이미 디스크를 떠난 것이
아니라 대조에 걸린 것을 말합니다. 그런 삭제는 deletes_pending이
true인 채로 돌아오며, 이는 둘 중 더 약한 보장이 적용되고 있다고
mcpd가 알려 주는 것입니다. 이 백엔드에서 데이터셋 케이스는 예외입니다. 케이스는
뮤테이션이 아니라 자기 키로 다시 쓰이므로, 비워진 케이스가 응답을 보낸 순간부터
모든 읽기에 그대로 나옵니다. 뮤테이션이었다면 끝날 때까지 옛 텍스트를 읽을 수
있었을 것입니다.
어떤 시점까지 데이터가 사라졌다고 누군가에게 확인해 주어야 한다면, 적어 둘 차이가 바로 이것입니다. ClickHouse에서는 답하기 전에 서버에서 뮤테이션이 끝났는지 확인하십시오.
포트가 닿을 수 있게 되기 전에
마스킹은 트레이스 안의 값을 보호합니다. 누가 그 트레이스를 읽을 수 있는지에
대해서는 아무것도 하지 않습니다. mcpd는 수집이나 조회 API가 열린 채로 루프백이
아닌 주소에 바인딩하면 시작할 때 경고합니다. 그 상태에서는 저장된 프롬프트와
응답을 그 포트에 닿을 수 있는 누구나 읽을 수 있기 때문입니다. 먼저
--ingest-key와 --read-key를 설정하고,
Docker와 Kubernetes를 읽으십시오.