Harness Academy
Tài liệu gốc 25 9 phútTiếng Việt + English
docs/adr/0015-environment-bucket-secrets.mdXem bản gốc
Ngôn ngữ bài đọc
Bản dịch tiếng Việt

Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.

0015. Bí mật về môi trường-nhóm - một bề mặt cấu hình, hai cơ chế tiêm

Trạng thái: Đã chấp nhận Ngày: 2026-07-13 Đã sửa đổi: 2026-07-13 — §6 không được tranh luận: quyết định rằng các quy tắc Thông tin xác thực-Proxy sẽ được giải quyết {{ settings_field }} mẫu từ ngậm nước Settings (sửa đổi ADR-0011 §6). ADR-0016 sau đó xóa hoàn toàn Proxy thông tin xác thực nên không còn quy tắc nào để giải quyết. Mọi thứ khác ở đây viết tắt - §6 chỉ nói về nơi quy tắc proxy đọc giá trị của nó từ, không bao giờ nói về bề mặt cấu hình chính nó, đó chính xác là những gì ADR-0016 giữ.

Bối cảnh

decode đã phát triển ba nút bí mật chồng chéo trên đường dẫn headless (ADR-0008 §5): RUNTIME_SECRET_STORE_MODEL_KEY (khóa nhà cung cấp từ bí mật Kitaru khi xây dựng mô hình), RUNTIME_SECRET_STORE_CONFIG (hydrat hóa toàn bộ bề mặt, chỉ không có đầu, được lật bằng mô-đun toàn cầu từ runtime/flow.py) và RUNTIME_SECRET_NAME (tên bí mật được chia sẻ). Trong khi đó Proxy thông tin xác thực (ADR-0011 §6, ADR-0012 §10) đã giải quyết {{ secret-name.key }} mẫu tiêu đề thông qua giây, độc lập kitaru.get_secret đường may.

Kết quả: ba cách để thông tin xác thực tham gia vào quy trình, hai trong số đó chỉ không có đầu, không có cách nào biểu thị câu hỏi mà người vận hành thực sự hỏi — đây là môi trường nào? Các nút bấm cũng có thể gây nhầm lẫn cho nhau (khóa mẫu được gửi dưới tên "Proxy thông tin xác thực" và bị nhầm với tính năng chèn tiêu đề Proxy thông tin xác thực thường đủ để đảm bảo việc đổi tên riêng của nó) và của nhà phát triển .env có thể âm thầm lấp đầy một chìa khóa bị thiếu trong bí mật triển khai, che giấu khoảng trống cung cấp cho đến khi sản xuất.

Settings (pydantic-settings) đã là trình đọc cấu hình duy nhất. Những gì còn thiếu là một đĩa đơn, câu trả lời theo hình dạng môi trường cho ở đâu Settings nhận được các giá trị của nó.

Quyết định

Settings là NGUỒN SỰ THẬT DUY NHẤT. Cả hai cơ chế đều tải vào nó và không có mã nào đọc thông tin xác thực từ bất cứ nơi nào khác.

  1. DECODE_ENV chọn cơ chế tiêm và không chọn gì khác. decode_env: Literal["local","dev","staging","prod"] = "local". Đó là biến bootstrap: nó quyết định liệu nhóm có được đọc hay không, vì vậy nó không bao giờ có thể đến từ nhóm. Nó được giải quyết ngoài băng tần (phân tích cú pháp tập tin dotenv, lớp phủ os.environ; process env thắng, khớp với mọi cài đặt khác) và giá trị được giải quyết được đưa trở lại ruộng nên cổng và ruộng không bao giờ có thể tách rời nhau.

  2. Hai chuỗi nguồn. local (mặc định): init > process env > .env > defaults - hành vi ngày nay, kitaru chưa bao giờ được nhập khẩu. Từ xa: init > process env > Environment Bucket > defaults — .env được thả từ chuỗi hoàn toàn, do đó, một khóa bị thiếu trong nhóm bị lỗi lớn tiếng thay vì được lấp đầy một cách âm thầm từ tập tin của nhà phát triển. Đây là điểm của việc có môi trường.

  3. Tên nhóm được lấy từ: decode-<env>. Không có nút ghi đè — ít thứ bị trôi hơn và "DECODE_ENV=staging chĩa vào thùng sản phẩm" trở nên không thể diễn tả được.

  4. Nghỉ giải lao sạch sẽ. runtime_secret_name, runtime_secret_store_config, runtime_secret_store_model_key (và bí danh đã nghỉ hưu từ lâu RUNTIME_CREDENTIALS_PROXY_ENABLED) bị xóa, không có miếng chêm và không có lỗi nhanh bảo vệ - một sự lựa chọn có chủ ý; extra="ignore" nuốt những mục cũ một cách im lặng. Việc loại bỏ được thực hiện ồn ào trong .env.example, ADR này, và 06_credentials.md thay vào đó. Xóa núm phím mẫu cũng xóa resolve_provider_key_from_secret_store / SECRET_STORE_KEY và các chuyến bay trước cli được xây dựng trên chúng: khóa nhà cung cấp bây giờ chỉ đơn giản đến từ Settings, ngậm nước theo cơ chế nào đang hoạt động. build_agent(flow_mode=…) giữ nó flow_mode tham số - nó vẫn chọn HTTP không tồn tại client (ADR-0010 §3) — nhưng nguồn cung cấp khóa không còn thay đổi theo chế độ nữa.

  5. Quá trình hydrat hóa có phạm vi quy trình và không phụ thuộc vào bề mặt. decode_env != "local" cổng thay thế chuyển đổi toàn cầu mô-đun headless: TUI và headless decode run / decode replay hydrat giống hệt nhau, tại công trình xây dựng Singleton. Bất biến cũ "trần trụi" decode không bao giờ nhập khẩu kitaru" được phát biểu lại: tại DECODE_ENV=local (mặc định), decode không bao giờ nhập kitaru. Một nhóm bị thiếu hoặc không thể truy cập được (bao gồm cả trình nền cục bộ Kitaru đang ngừng hoạt động) không được làm hỏng quá trình nhập: nguồn ghi lại lỗi và chuỗi khởi động REPL và bề mặt trước chuyến bay headless nó là MỘT dòng thân thiện đặt tên cho bản sửa lỗi (make sync-secrets ENV=<env>), thoát ra khác 0, không truy nguyên - mô hình hỏng hóc của ngôi nhà.

  6. Proxy thông tin xác thực được giải quyết từ Settings. Mẫu quy tắc proxy đặt tên cho trường Cài đặt ** — {"Authorization": "Bearer {{ sandbox_git_token }}"} - giải quyết phía máy chủ từ đối tượng ngậm nước. _resolve_templates, cái {{ name.key }} biểu mẫu và phía proxy kitaru.get_secret bị xóa; build_credential_map() trở thành một hàm thuần túy của settings (không có mạng, không có sơ khai cửa hàng trong các thử nghiệm của nó). github_token_rules() không bị ảnh hưởng. Sau đó, Chỉ của Kitaru get_secret đường nối trong toàn bộ cơ sở mã là nguồn cài đặt Nhóm môi trường.

  7. Tập lệnh đồng bộ là người viết duy nhất. scripts/sync_secrets.py (make sync-secrets ENV=<env>) gương .env → xô trong MỘT kitaru secrets set decode-<env> --private --KEY=value … gọi. Thực tế đã được xác minh này hình dạng treo trên: kitaru secrets set THAY THẾ toàn bộ bộ khóa — bản cập nhật một phần sẽ hủy các khóa khác — vì vậy toàn bộ bề mặt hoặc không có gì là cách ghi an toàn duy nhất và nó làm cho nhóm trở thành một bản sao chính xác của tệp. Ghi đè in khác biệt CHỈ TÊN KHÓA (không bao giờ có giá trị) và yêu cầu xác nhận (--yes đối với CI). Chỉ một chiều: tập tin là nguồn gốc của sự thật, Kitaru thì không bao giờ như vậy.

  8. Dự án Opik tuân theo môi trường. opik_project_name mặc định là f"decode-{decode_env}"; một được thiết lập rõ ràng OPIK_PROJECT_NAME (en/ .env /buck) luôn thắng, được phát hiện qua pydantic's model_fields_set (các giá trị do nguồn cung cấp nằm trong đó; các giá trị được áp dụng mặc định không được xác minh dựa trên đã cài đặt pydantic-settings 2.14.2), không bao giờ so sánh trọng điểm.

  9. Trôi là lỗi CI. Kiểm tra đơn vị khẳng định .env.example KEY= dòng ≡ Settings tên trường, cả hai chỉ đường, không có danh sách cho phép — mọi trường đều được ghi lại, mọi khóa được ghi lại đều có thật. Ba tiến trình-env-chỉ các biến toán tử (DECODE_LOG_FILE, MODAL_TOKEN_ID, MODAL_TOKEN_SECRET) trở thành bình luận văn xuôi; họ là đọc từ os.environ, không bao giờ từ .env, vậy hiện tại của họ KEY= Dù sao thì các dòng cũng đã gây hiểu nhầm.

Không có bàn thắng. DECODE_ENV không thay đổi thư mục phiên, đường dẫn nhật ký hoặc MEMORY.md. Không có miếng chêm tương thích hoặc cảnh báo không dùng nữa cho các nút đã xóa. Không có xô → .env kéo. Không có môi trường per-PR / phù du — Literal đã bị đóng, vì vậy môi trường mới là sự thay đổi mã một cách có chủ ý.

Sửa đổi các ADR trước đó.

  • ADR-0008 §5 được sửa đổi: nguồn Cấu hình cửa hàng bí mật và độ phân giải bí mật khóa mô hình mà nó đã chỉ định (với RUNTIME_SECRET_NAME / RUNTIME_SECRET_STORE_CONFIG / RUNTIME_SECRET_STORE_MODEL_KEY) bị xóa và được thay thế bởi DECODE_ENVNhóm môi trường có kiểm soát (ADR §§1–5 này). “Giá trị đất đai trong Settings chỉ, không bao giờ os.environ; env thực sự thắng" các bất biến không thay đổi.
  • ADR-0011 §6 / ADR-0012 §10 được sửa đổi: quy tắc proxy không còn được giải quyết {{ secret-name.key }} qua kitaru.get_secret; tên mẫu các trường Cài đặt và giải quyết từ cấu hình ngậm nước (ADR §6 này). các yêu cầu công nhân không bao giờ giữ token, cấu trúc liên kết vùng chứa và SANDBOX_GIT_TOKEN sự đánh đổi không thay đổi.

Sơ đồ

flowchart TB
    subgraph LOCAL["DECODE_ENV=local (default)"]
        DOTENV[".env file<br/>(dotenv source)"]
    end
    subgraph REMOTE["DECODE_ENV=dev | staging | prod"]
        BUCKET["Environment Bucket<br/>Kitaru secret decode-&lt;env&gt;"]
        SRC["EnvironmentBucketSettingsSource<br/>(the ONLY kitaru get_secret seam)"]
        BUCKET --> SRC
    end
    ENVFILE[".env (developer file)"] -. "one-way mirror<br/>make sync-secrets ENV=&lt;env&gt;<br/>ONE kitaru secrets set (full replace)" .-> BUCKET
    PROC["process env<br/>(always wins)"]
    DEF["field defaults"]
    BOOT{{"DECODE_ENV<br/>bootstrap: dotenv, overlaid by process env<br/>(read out-of-band)"}}
    SETTINGS[("Settings<br/>SINGLE SOURCE OF TRUTH")]

    BOOT -->|selects chain| SETTINGS
    PROC --> SETTINGS
    DOTENV -->|"local only<br/>(DROPPED at remote)"| SETTINGS
    SRC -->|remote only| SETTINGS
    DEF --> SETTINGS

    SETTINGS --> FACTORY["agent/factory.py<br/>provider API keys"]
    SETTINGS --> PROXY["sandbox/proxy.py<br/>build_credential_map()<br/>{{ settings_field }} templates — pure"]
    SETTINGS --> OPIK["observability<br/>opik_project_name = decode-&lt;env&gt;"]
    SETTINGS --> REST["every other reader<br/>(TUI + headless alike)"]

    classDef local fill:#d4edda,stroke:#2e7d32,color:#1b5e20;
    classDef remote fill:#d6e4ff,stroke:#1565c0,color:#0d47a1;
    classDef truth fill:#fff3cd,stroke:#b8860b,color:#7a5c00,stroke-width:3px;
    classDef consumer fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c;
    classDef boot fill:#ffe0b2,stroke:#e65100,color:#bf360c;
    class DOTENV,LOCAL local;
    class BUCKET,SRC,REMOTE remote;
    class SETTINGS truth;
    class FACTORY,PROXY,OPIK,REST consumer;
    class BOOT,PROC,DEF,ENVFILE boot;

hậu quả

Tích cực. Một câu hỏi ("môi trường nào?") thay thế ba nút bấm. Khoảng trống cung cấp thất bại lớn khi khởi động với bản sửa lỗi được đặt tên, thay vì bị nhà phát triển che giấu .env. Proxy thông tin xác thực mất kitaru thứ hai đường may, và các bài kiểm tra đơn vị của nó làm mất các cuống lưu trữ của chúng — build_credential_map() trở thành một hàm thuần túy. .env.example không thể nói dối được nữa (thử trôi dạt). Opik tự sắp xếp dấu vết theo môi trường. Chiếc xô luôn là tấm gương trung thực của tệp - ngữ nghĩa ghi thay thế hoàn toàn chuyển từ một khẩu súng ngắn thành cơ chế.

Tiêu cực / chấp nhận.

  • Một điều khiển từ xa DECODE_ENV nhập kitaru (và ngăn xếp ZenML) tại thời điểm nhập cài đặt — khởi động nặng hơn và chạm vào mạng/DB trước lời nhắc đầu tiên, trong TUI cũng như headless. Đã được chấp nhận: đó chính xác là những gì "điều khiển từ xa môi trường" có nghĩa là, và local (mặc định) vẫn giữ nguyên byte cho đến ngày hôm nay.
  • cũ RUNTIME_SECRET_* các mục được âm thầm bỏ qua (extra="ignore"). Giảm nhẹ bằng các tài liệu ồn ào, không phải bằng mã — một sự lựa chọn có chủ ý và là nơi mà thiết kế này đánh đổi sự an toàn để lấy sự đơn giản.
  • Nhóm môi trường không thể cung cấp token tài khoản phương thức. MODAL_TOKEN_ID / MODAL_TOKEN_SECRET là đọc từ os.environ (bởi cli.pybảo vệ của và bởi chính SDK phương thức), không bao giờ từ Settings - và cho ăn chúng từ thùng sẽ yêu cầu viết bí mật Kitaru vào os.environ, phá vỡ bất biến giữ model được chọn bash từ việc kế thừa bí mật. Vì vậy, trong môi trường từ xa, xác thực phương thức vẫn phải đến từ xử lý env hoặc ~/.modal.toml. (MODAL_PROXY_TOKEN_ID / _SECRET — tiêu đề xác thực điểm cuối được cung cấp — are Settings ruộng và hydrat hóa từ xô một cách bình thường.)
  • Tập lệnh đồng bộ chuyển các giá trị thông qua kitaru secrets set argv, hiển thị nhanh với máy chủ ps. Phía người vận hành, một máy duy nhất, được chấp nhận cho giải pháp an toàn thay thế một cuộc gọi mà nó mua.
  • Các thử nghiệm sẽ mất tên bí mật duy nhất cho mỗi thử nghiệm (tên nhóm được dẫn xuất), do đó việc cách ly chỉ dựa trên tmp-path ZenML cố định cửa hàng.
  • Môi trường mới là sự thay đổi mã ( Literal đã đóng) — có chủ ý, xem mục Không có mục tiêu.
Mục lục nguồn