Skip to content

Commit ef05ae5

Browse files
Pigbibicodex
andcommitted
Add provider admin usage snapshots
Co-Authored-By: Codex <noreply@openai.com>
1 parent 7003a12 commit ef05ae5

14 files changed

Lines changed: 1016 additions & 34 deletions

.github/workflows/vps_codex_service_ops.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,9 @@ jobs:
4646
CODEX_AUDIT_SERVICE_MODEL: ${{ vars.CODEX_AUDIT_SERVICE_MODEL }}
4747
CODEX_AUDIT_SERVICE_REASONING_EFFORT: ${{ vars.CODEX_AUDIT_SERVICE_REASONING_EFFORT }}
4848
CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE: "1"
49+
CODEX_AUDIT_SERVICE_OPENAI_USAGE_WINDOW_DAYS: "7"
50+
CODEX_AUDIT_SERVICE_ANTHROPIC_USAGE_WINDOW_DAYS: "7"
51+
OPENAI_ADMIN_KEY: ${{ secrets.OPENAI_ADMIN_KEY }}
52+
ANTHROPIC_ADMIN_KEY: ${{ secrets.ANTHROPIC_ADMIN_KEY }}
4953
CODEX_AUDIT_SERVICE_TOKEN: ${{ secrets.CODEX_AUDIT_SERVICE_TOKEN }}
5054
run: bash scripts/deploy_codex_audit_service.sh "${{ inputs.mode }}"

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ CODEX_AUDIT_SERVICE_AUDIENCE=quant-codex-audit \
105105
CODEX_AUDIT_SERVICE_MODEL=gpt-5.4 \
106106
CODEX_AUDIT_SERVICE_REASONING_EFFORT=auto \
107107
CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE=1 \
108+
CODEX_AUDIT_SERVICE_OPENAI_USAGE_WINDOW_DAYS=7 \
109+
CODEX_AUDIT_SERVICE_ANTHROPIC_USAGE_WINDOW_DAYS=7 \
108110
python3 -m service.ai_gateway_service
109111
```
110112

@@ -117,6 +119,20 @@ When `CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE=1`, the dashboard reads a
117119
sanitized Codex rate-limit snapshot through the local authenticated Codex
118120
app-server; API-key rows remain internal estimates unless a platform usage
119121
provider is configured separately.
122+
Set `OPENAI_ADMIN_KEY` to an OpenAI Admin API key to add a sanitized
123+
GPT/OpenAI completions Usage snapshot to `/v1/ai/quota`. Optional
124+
`CODEX_AUDIT_SERVICE_OPENAI_ADMIN_API_KEY_IDS` can limit that snapshot to
125+
specific API key IDs; never store raw API keys in that filter. OpenAI
126+
organization-wide costs are kept in a separate `organization_costs` field and
127+
are not mixed into the completions usage row.
128+
Set `ANTHROPIC_ADMIN_KEY` to an Anthropic Admin API key to add a sanitized
129+
Claude organization Usage/Cost snapshot. Do not reuse the normal
130+
`ANTHROPIC_API_KEY`; Anthropic usage/cost reporting requires an Admin API key.
131+
Optional `CODEX_AUDIT_SERVICE_ANTHROPIC_ADMIN_API_KEY_IDS` and
132+
`CODEX_AUDIT_SERVICE_ANTHROPIC_ADMIN_WORKSPACE_IDS` filter usage by IDs; costs
133+
are omitted when those filters are set to avoid mixing filtered usage with an
134+
unfiltered cost total. The deploy script stores admin keys in a root-only
135+
`0600` EnvironmentFile, not directly in the systemd unit.
120136

121137
If no custom domain is available, `cloudflare/codex-audit-proxy/` contains a minimal Cloudflare Worker that can publish a free `workers.dev` HTTPS entry point while keeping the VPS origin URL in a Cloudflare secret. The production service path is async: submit `POST /v1/codex-audit/jobs`, then poll `GET /v1/codex-audit/jobs/{job_id}`. See `docs/async_service_deployment.md` for the deployment and open-source repository checklist.
122138

cloudflare/ai-gateway-dash/src/index.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,12 @@ function healthReasonText(r){const path=r.path||"endpoint";if(r.reason==="error_
172172
function renderHealth(h){setStatus(h.status||"unknown");setUpdated("health-updated");const target=document.getElementById("health"),endpoints=h.endpoints||[],reasons=h.degradation_reasons||[],total=endpoints.reduce((s,i)=>s+(Number(i.total)||0),0),errors=endpoints.reduce((s,i)=>s+(Number(i.errors)||0),0),p95=Math.max(0,...endpoints.map(i=>Number(i.p95_ms)||0)),details=el("div","");append(details,statRow("接口数量",endpoints.length,"info"),statRow("总请求",fmtNum(total),""),statRow("错误",fmtNum(errors),errors?"err":"ok"),statRow("最高 P95",fmtNum(p95)+" ms",p95>30000?"err":p95>10000?"warn":"ok"));if(reasons.length){reasons.slice(0,3).forEach((reason,i)=>append(details,statRow(i?"降级原因 "+(i+1):"降级原因",healthReasonText(reason),clsStatus(reason.severity||h.status))));if(reasons.length>3)append(details,statRow("更多原因","+"+fmtNum(reasons.length-3),"warn"))}else if(h.last_error&&h.last_error.message){append(details,statRow("最近错误",String(h.last_error.message).slice(0,80),"warn"))}clear(target);append(target,append(el("div","metric-line"),el("div","big ",statusText(h.status||"unknown")),el("span","delta "+clsStatus(h.status||"unknown"),fmtNum(Math.round((h.uptime_seconds||0)/3600))+" h")),details)}
173173
function quotaTotalRow(label,d){const row=el("div","stat-row"),used=Number(d&&d.total_cost_usd)||0;append(row,el("span","stat-label",label),el("span","stat-value info",fmtUSD(used)));return row}
174174
function codexAccountRow(d){const row=el("div","stat-row"),r=d&&d.rate_limits||{},p=r.primary||{},s=r.secondary||{},credits=r.credits||{},parts=[];if(p.used_percent!==null&&p.used_percent!==undefined)parts.push((p.window_duration_mins?Math.round(p.window_duration_mins/60)+"h":"主窗口")+" "+p.used_percent+"%");if(s.used_percent!==null&&s.used_percent!==undefined)parts.push((s.window_duration_mins?Math.round(s.window_duration_mins/1440)+"d":"次窗口")+" "+s.used_percent+"%");if(r.plan_type)parts.push(String(r.plan_type));if(credits.balance!==null&&credits.balance!==undefined)parts.push("credits "+credits.balance);append(row,el("span","stat-label","Codex 账户"),el("span","stat-value "+(Number(p.used_percent)>80?"err":Number(p.used_percent)>50?"warn":"ok"),parts.join(" · ")||"实时可用"));return row}
175+
function providerAccountRow(label,d,usageKey){const row=el("div","stat-row"),c=d&&d.costs||{},u=d&&d[usageKey]||{},days=Number(d&&d.window_days)||7,currency=String(c.currency||"usd").toUpperCase(),cost=Number(c.total_cost)||0,tokens=Number(u.total_tokens)||((Number(u.input_tokens)||0)+(Number(u.output_tokens)||0)),requests=Number(u.num_model_requests)||0,parts=[];if(c.total_cost!==null&&c.total_cost!==undefined)parts.push(days+"d "+(currency==="USD"?fmtUSD(cost):cost.toFixed(2)+" "+currency));if(requests)parts.push(fmtNum(requests)+" req");if(tokens)parts.push(fmtNum(tokens)+" tokens");if(d&&d.usage_surface)parts.push(String(d.usage_surface));if(d&&d.filtered_project_count)parts.push(fmtNum(d.filtered_project_count)+" project");if(d&&d.filtered_api_key_count)parts.push(fmtNum(d.filtered_api_key_count)+" key");if(d&&d.filtered_workspace_count)parts.push(fmtNum(d.filtered_workspace_count)+" workspace");append(row,el("span","stat-label",label),el("span","stat-value info",parts.join(" · ")||"实时可用"));return row}
176+
function organizationCostRow(label,d,days){const row=el("div","stat-row"),currency=String(d&&d.currency||"usd").toUpperCase(),cost=Number(d&&d.total_cost)||0,parts=[(Number(days)||7)+"d org "+(currency==="USD"?fmtUSD(cost):cost.toFixed(2)+" "+currency)];append(row,el("span","stat-label",label),el("span","stat-value info",parts.join(" · ")));return row}
175177
function quotaHasUsage(d){return Boolean(Number(d&&d.total_cost_usd)||Number(d&&d.calls)||Number(d&&d.tokens_input)||Number(d&&d.tokens_output)||(d&&d.calls_incomplete))}
176-
function quotaUsageRow(label,d,extra){const row=el("div","stat-row"),calls=Number(d&&d.calls)||0,used=Number(d&&d.total_cost_usd)||0,tokens=Number(d&&d.tokens_input)||0,callText=d&&d.calls_incomplete?"≥ "+fmtNum(calls):fmtNum(calls),detail=fmtUSD(used)+" · "+callText+" 次"+(tokens?" · "+fmtNum(tokens)+" tokens":"")+(extra?" · "+extra:"");append(row,el("span","stat-label",label),el("span","stat-value info",detail));return row}
178+
function quotaUsageRow(label,d,extra){const row=el("div","stat-row"),calls=Number(d&&d.calls)||0,used=Number(d&&d.total_cost_usd)||0,tokens=Number(d&&d.tokens_input)||0,callText=d&&d.calls_incomplete?(calls?"≥ "+fmtNum(calls):"未知次数"):fmtNum(calls),detail=fmtUSD(used)+" · "+callText+" 次"+(tokens?" · "+fmtNum(tokens)+" tokens":"")+(extra?" · "+extra:"");append(row,el("span","stat-label",label),el("span","stat-value info",detail));return row}
177179
function appendRepoQuotaRows(list,repos){for(const name of Object.keys(repos)){const d=repos[name]||{},used=Number(d.total_cost_usd)||0,budget=Number(d.daily_budget)||0,p=budget?used/budget*100:0,c=progressClass(p),item=el("div","quota-item"),meta=el("div",""),bar=el("div","bar"),fill=el("div","bar-fill "+c);fill.style.width=Math.max(0,Math.min(p,100))+"%";append(meta,el("div","quota-name",String(name).split("/").pop()||name),el("div","quota-meta",fmtUSD(used)+" / "+fmtUSD(budget)+" repo 日预算"));append(bar,fill);append(item,meta,bar,el("div","bar-label",Math.round(p)+"%"));list.appendChild(item)}}
178-
function renderQuota(q){setUpdated("quota-updated");const target=document.getElementById("quota"),repos=q.repos||{},repoCount=Object.keys(repos).length,summary=q.summary||null,account=summary&&summary.codex_account&&summary.codex_account.status==="available"?summary.codex_account:null,hasSummaryUsage=summary&&(account||quotaHasUsage(summary.combined)||quotaHasUsage(summary.api_key)||quotaHasUsage(summary.codex));clear(target);if(summary&&(repoCount||hasSummaryUsage)){const list=el("div","quota-list"),details=el("div","");appendRepoQuotaRows(list,repos);if(account)append(details,codexAccountRow(account));append(details,quotaTotalRow("合计估算",summary.combined||{}),quotaUsageRow("API Key 估算",summary.api_key||{}),quotaUsageRow("Codex 估算",summary.codex||{}));if(repoCount)target.appendChild(list);target.appendChild(details);target.appendChild(el("div","subtle","Codex 账户行来自本机 Codex rate-limit 快照;API Key、合计和 repo 行为内部用量估算/限流,不等同账户后台实时余额。"));return}if(!repoCount){empty(target,"暂无用量","当前窗口内没有记录到配额消耗。API Key 与 Codex 均无用量记录。");return}const list=el("div","quota-list");appendRepoQuotaRows(list,repos);target.appendChild(list)}
180+
function renderQuota(q){setUpdated("quota-updated");const target=document.getElementById("quota"),repos=q.repos||{},repoCount=Object.keys(repos).length,summary=q.summary||null,account=summary&&summary.codex_account&&summary.codex_account.status==="available"?summary.codex_account:null,openai=summary&&summary.openai_account&&summary.openai_account.status==="available"?summary.openai_account:null,anthropic=summary&&summary.anthropic_account&&summary.anthropic_account.status==="available"?summary.anthropic_account:null,hasSummaryUsage=summary&&(account||openai||anthropic||quotaHasUsage(summary.combined)||quotaHasUsage(summary.api_key)||quotaHasUsage(summary.codex)||quotaHasUsage(summary.legacy_unknown));clear(target);if(summary&&(repoCount||hasSummaryUsage)){const list=el("div","quota-list"),details=el("div","");appendRepoQuotaRows(list,repos);if(openai){append(details,providerAccountRow("GPT API 账户",openai,"completions"));if(openai.organization_costs)append(details,organizationCostRow("GPT 组织成本",openai.organization_costs,openai.window_days))}if(anthropic)append(details,providerAccountRow("Claude API 账户",anthropic,"messages"));if(account)append(details,codexAccountRow(account));append(details,quotaTotalRow("合计估算",summary.combined||{}),quotaUsageRow("API Key 估算",summary.api_key||{}),quotaUsageRow("Codex 估算",summary.codex||{}));if(quotaHasUsage(summary.legacy_unknown))append(details,quotaUsageRow("历史未拆分",summary.legacy_unknown||{},"未归属"));if(repoCount)target.appendChild(list);target.appendChild(details);target.appendChild(el("div","subtle","GPT/Claude API 账户行来自各自 Admin Usage/Cost API;GPT 组织成本单独展示,不与过滤后的 completions usage 混算;Codex 账户行来自本机 Codex rate-limit 快照;历史未拆分行为仅用于迁移提示,不归入 API Key 或 Codex 估算。"));return}if(!repoCount){empty(target,"暂无用量","当前窗口内没有记录到配额消耗。API Key 与 Codex 均无用量记录。");return}const list=el("div","quota-list");appendRepoQuotaRows(list,repos);target.appendChild(list)}
179181
function renderEffectiveness(e){setUpdated("effectiveness-updated");const target=document.getElementById("effectiveness"),rate=Number(e.improvement_rate)||0;clear(target);append(target,append(el("div","metric-line"),el("div","big blue",fmtPct(rate)),el("span","delta "+(rate>0.7?"ok":rate>0.4?"warn":"info"),"改善率")),append(el("div",""),statRow("已评估",e.evaluated||0,"info"),statRow("改善",e.improved||0,"ok"),statRow("退化",e.degraded||0,"err"),statRow("持平",e.neutral||0,""),statRow("待评估",e.pending||0,"info")))}
180182
function renderShadow(items){setUpdated("shadow-updated");const target=document.getElementById("shadow"),total=items.reduce((sum,item)=>sum+(Number(item.disagreement_count)||0),0);clear(target);if(!items.length){empty(target,"无活跃分歧","影子审计当前没有待复核分歧。");return}append(target,append(el("div","metric-line"),el("div","big violet",fmtNum(total)),el("span","delta warn","待复核")));for(const d of items.slice(0,5)){const row=el("div","stat-row"),value=el("span","stat-value warn");append(value,badge("warn",(d.disagreement_count||0)+"x"),document.createTextNode(" "+(d.ai_verdict||"")));append(row,el("span","stat-label",d.plugin||d.repo||"shadow"),value);target.appendChild(row)}}
181183
function renderChanges(items){setUpdated("changes-updated");const target=document.getElementById("changes");clear(target);if(!items.length){empty(target,"窗口内无变更","最近 7 天没有登记的变更记录。 ");return}const table=el("table",""),thead=el("thead",""),tr=el("tr","");for(const h of ["仓库","操作","效果","置信度","时间"])tr.appendChild(el("th","",h));thead.appendChild(tr);const tbody=el("tbody","");for(const c of items){const effect=c.effect||"pending",effectClass=effect==="improved"?"ok":effect==="degraded"?"err":"info",actionClass=c.action==="auto_merge"?"ok":c.action==="auto_pr"?"info":c.action?"violet":"warn",dt=c.created_at?new Date(c.created_at*1000).toLocaleDateString():"—",row=el("tr",""),repoName=String(c.repo||"").split("/").pop()||"—",repoCell=el("td","mono");if(c.external_url){const a=el("a","",repoName);a.href=c.external_url;a.target="_blank";a.rel="noreferrer";a.style.color="#93c5fd";a.style.textDecoration="none";repoCell.appendChild(a)}else repoCell.textContent=repoName;append(row,repoCell,append(el("td",""),badge(actionClass,c.action||"change")),el("td","stat-value "+effectClass,effect),el("td","mono",fmtPct(c.confidence||0)),el("td","mono",dt));tbody.appendChild(row)}append(table,thead,tbody);target.appendChild(table)}

docs/async_service_deployment.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ CODEX_AUDIT_SERVICE_AUDIENCE=quant-codex-audit \
6464
CODEX_AUDIT_SERVICE_MODEL=gpt-5.4 \
6565
CODEX_AUDIT_SERVICE_REASONING_EFFORT=auto \
6666
CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE=1 \
67+
CODEX_AUDIT_SERVICE_OPENAI_USAGE_WINDOW_DAYS=7 \
68+
CODEX_AUDIT_SERVICE_ANTHROPIC_USAGE_WINDOW_DAYS=7 \
6769
CODEX_AUDIT_SERVICE_JOB_DIR=/var/lib/codex-audit-bridge/jobs \
6870
bash scripts/deploy_codex_audit_service.sh deploy
6971
```
@@ -75,6 +77,20 @@ With `CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE=1`, `/v1/ai/quota` includes a
7577
sanitized Codex account rate-limit snapshot read from the local Codex
7678
app-server. This does not expose Codex auth tokens and should stay behind the
7779
existing dashboard authentication.
80+
With `OPENAI_ADMIN_KEY` set, `/v1/ai/quota` also includes a sanitized OpenAI
81+
completions Usage snapshot. Store the Admin API key only as a secret;
82+
the deploy script writes it to a root-only `0600` EnvironmentFile instead of
83+
embedding it in the public systemd unit. Use `CODEX_AUDIT_SERVICE_OPENAI_ADMIN_API_KEY_IDS`
84+
only for API key IDs, not raw API keys. OpenAI organization-wide costs are kept
85+
in a separate `organization_costs` field and are not mixed into the completions
86+
usage row.
87+
With `ANTHROPIC_ADMIN_KEY` set, `/v1/ai/quota` also includes a sanitized Claude
88+
organization Usage/Cost snapshot. Store it separately from the normal
89+
`ANTHROPIC_API_KEY`; the usage/cost endpoints require an Admin API key. Use
90+
`CODEX_AUDIT_SERVICE_ANTHROPIC_ADMIN_API_KEY_IDS` and
91+
`CODEX_AUDIT_SERVICE_ANTHROPIC_ADMIN_WORKSPACE_IDS` only for IDs, never raw API
92+
keys. When those filters are set, costs are omitted to avoid mixing filtered
93+
usage with an unfiltered cost total.
7894
Set `CODEX_AUDIT_SERVICE_REASONING_EFFORT` only when a hard override is needed;
7995
unset or `auto` keeps task-complexity routing.
8096

scripts/deploy_codex_audit_service.sh

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ ALLOWED_REFS="${CODEX_AUDIT_SERVICE_ALLOWED_REFS:-refs/heads/main,refs/pull/*/me
1313
ALLOWED_REPOSITORY_VISIBILITIES="${CODEX_AUDIT_SERVICE_ALLOWED_REPOSITORY_VISIBILITIES:-public}"
1414
ALLOWED_SOURCE_REPOSITORIES="${CODEX_AUDIT_SERVICE_ALLOWED_SOURCE_REPOSITORIES:-QuantStrategyLab/AIAuditBridge,QuantStrategyLab/CodexAuditBridge,QuantStrategyLab/CryptoLivePoolPipelines,QuantStrategyLab/HkEquitySnapshotPipelines,QuantStrategyLab/UsEquitySnapshotPipelines,QuantStrategyLab/ResearchSignalContextPipelines}"
1515
JOB_DIR="${CODEX_AUDIT_SERVICE_JOB_DIR:-/var/lib/codex-audit-bridge/jobs}"
16+
ADMIN_ENV_FILE="${CODEX_AUDIT_SERVICE_ADMIN_ENV_FILE:-/etc/codex-audit-bridge/admin.env}"
1617
AUDIT_MODEL="${CODEX_AUDIT_SERVICE_MODEL:-}"
1718
AUDIT_REASONING_EFFORT="${CODEX_AUDIT_SERVICE_REASONING_EFFORT:-}"
1819
CODEX_ACCOUNT_USAGE="${CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE:-1}"
20+
OPENAI_USAGE_WINDOW_DAYS="${CODEX_AUDIT_SERVICE_OPENAI_USAGE_WINDOW_DAYS:-7}"
21+
ANTHROPIC_USAGE_WINDOW_DAYS="${CODEX_AUDIT_SERVICE_ANTHROPIC_USAGE_WINDOW_DAYS:-7}"
1922
NGINX_CONFIG="${CODEX_AUDIT_SERVICE_NGINX_CONFIG:-}"
2023

2124
require_sudo() {
@@ -57,7 +60,7 @@ systemctl_environment_brief() {
5760
| sed 's/^Environment=//' \
5861
| tr ' ' '\n' \
5962
| sed -E "s/^[\"']//; s/[\"']$//" \
60-
| grep -E '^CODEX_AUDIT_SERVICE_(ALLOWED_|AUDIENCE=|HOST=|PORT=|JOB_DIR=|QUOTA_STORE=|CODEX_ACCOUNT_USAGE=|SANDBOX=|MODEL=|REASONING_EFFORT=)' \
63+
| grep -E '^CODEX_AUDIT_SERVICE_(ALLOWED_|AUDIENCE=|HOST=|PORT=|JOB_DIR=|QUOTA_STORE=|CODEX_ACCOUNT_USAGE=|OPENAI_USAGE_WINDOW_DAYS=|ANTHROPIC_USAGE_WINDOW_DAYS=|SANDBOX=|MODEL=|REASONING_EFFORT=)' \
6164
| mask_infra || true
6265
fi
6366
}
@@ -188,6 +191,29 @@ install_service_package() {
188191
sudo find "${DEPLOY_DIR}/service" -type f -exec chmod 0644 {} +
189192
}
190193

194+
write_admin_env_file_if_needed() {
195+
if [ -z "${OPENAI_ADMIN_KEY:-}" ] && [ -z "${ANTHROPIC_ADMIN_KEY:-}" ]; then
196+
sudo rm -f "$ADMIN_ENV_FILE"
197+
return
198+
fi
199+
local tmp
200+
tmp="$(mktemp)"
201+
trap 'rm -f "$tmp"' RETURN
202+
chmod 0600 "$tmp"
203+
{
204+
if [ -n "${OPENAI_ADMIN_KEY:-}" ]; then
205+
printf 'OPENAI_ADMIN_KEY=%s\n' "$OPENAI_ADMIN_KEY"
206+
fi
207+
if [ -n "${ANTHROPIC_ADMIN_KEY:-}" ]; then
208+
printf 'ANTHROPIC_ADMIN_KEY=%s\n' "$ANTHROPIC_ADMIN_KEY"
209+
fi
210+
} >"$tmp"
211+
sudo install -d -m 0700 "$(dirname "$ADMIN_ENV_FILE")"
212+
sudo install -m 0600 -o root -g root "$tmp" "$ADMIN_ENV_FILE"
213+
rm -f "$tmp"
214+
trap - RETURN
215+
}
216+
191217
write_audit_service_unit() {
192218
local runner_user runner_home
193219
runner_user="$(id -un)"
@@ -227,7 +253,10 @@ Environment=CODEX_AUDIT_SERVICE_ALLOWED_SOURCE_REPOSITORIES=${ALLOWED_SOURCE_REP
227253
Environment=CODEX_AUDIT_SERVICE_JOB_DIR=${JOB_DIR}
228254
Environment=CODEX_AUDIT_SERVICE_QUOTA_STORE=${JOB_DIR}/quota.json
229255
Environment=CODEX_AUDIT_SERVICE_CODEX_ACCOUNT_USAGE=${CODEX_ACCOUNT_USAGE}
256+
Environment=CODEX_AUDIT_SERVICE_OPENAI_USAGE_WINDOW_DAYS=${OPENAI_USAGE_WINDOW_DAYS}
257+
Environment=CODEX_AUDIT_SERVICE_ANTHROPIC_USAGE_WINDOW_DAYS=${ANTHROPIC_USAGE_WINDOW_DAYS}
230258
Environment=CODEX_AUDIT_SERVICE_SANDBOX=read-only
259+
EnvironmentFile=-${ADMIN_ENV_FILE}
231260
${audit_model_line}
232261
${audit_reasoning_effort_line}
233262
${audit_token_line}
@@ -479,6 +508,7 @@ deploy() {
479508
install_file "scripts/codex_audit_service.py" "${DEPLOY_DIR}/scripts/codex_audit_service.py" "0755"
480509
install_service_package
481510
sudo install -d -m 0700 -o "$runner_user" -g "$runner_user" "$JOB_DIR"
511+
write_admin_env_file_if_needed
482512
write_audit_service_unit
483513
write_managed_audit_service_dropin
484514
sudo systemctl daemon-reload

service/adapters/codex_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from dataclasses import dataclass
1717
from pathlib import Path
1818

19-
SECRET_ENV_MARKERS = ("TOKEN", "SECRET", "PASSWORD", "PRIVATE_KEY", "CREDENTIAL", "API_KEY")
19+
SECRET_ENV_MARKERS = ("TOKEN", "SECRET", "PASSWORD", "PRIVATE_KEY", "CREDENTIAL", "API_KEY", "ADMIN_KEY")
2020
CODEX_REASONING_EFFORTS = frozenset({"minimal", "low", "medium", "high", "xhigh"})
2121

2222

0 commit comments

Comments
 (0)