v7 mech-2: split scorecard into code/production/product tables

(cherry picked from commit 67b7f5e42d001b655aef3e04e1d3c1d98166b98f)

Reconcile-port: handler_admin.py hunks redirected into cloud/server.py _audit_scorecard (target keeps 6-mixin split; scorecard module itself applied cleanly).
This commit is contained in:
host committed 2026-11-03 02:49:27 +00:00
1 parent 19fe4fc7e1
commit f8a6a9d258
3 files changed
+526 -33

No files matched your search

+209 -33
View File
@@ -67,6 +67,16 @@
每个维的证据字段见各 _score_* 函数的 docstring。
调用方必须带来源、时间、检查名;本模块不自动从测试文件、
摘要文档、PR 描述里拼凑分数。
三张表拆分(v7 机制第 2 项,见 _SCORERS 后的注释):
build_code_scorecard:代码证据 4 维,不含生产项;
build_production_scorecard:生产证据 3 维,缺项不拉低代码表,
可选 user_side_items 占位证据(pending 即挡住生产表 overall);
build_product_scorecard:全部 7 维 + 真实产品轮门禁,无真实
产品轮证据时恒 not_pass;这只是评分卡输入结构拆分,
不代表任何产品功能已落地。build_scorecard 的返回 dict
同时带 code/production/product 三个子对象,GET /audit-scorecard
端点返回的示例卡因此也带这三个子对象(端点已接线)。
"""
from __future__ import annotations
@@ -605,46 +615,79 @@ def verify_signature(evidence_bytes, signature, verifier=None):
return {"verified": False, "reason": "verifier_rejected"}
def build_scorecard(evidence, thresholds=None, rubric_version=None,
baseline_head=None, evidence_rows=None):
"""算出 7 维评分卡。evidence 缺键按空证据处理(该维记 None)。
# ---------------------------------------------------------------------------
# 三张表拆分(v7 机制第 2 项;仅评分卡输入结构拆分,不代表产品功能落地)
#
# 维分配(写死,不按调用方喜好重分;理由见各表注释):
# - 代码表 CODE_DIMENSION_IDS:delivery_quality、gate_audit、
# arch_contract、test_coverage。证据全部来自代码侧:交付指标、
# 门禁/审计、架构契约、测试覆盖——本地/代码审计即可验证,
# 不需要生产部署、真实 App、第二主机或用户侧拍板。
# - 生产表 PRODUCTION_DIMENSION_IDS:security_ledger、cost_quota、
# ops_scale。证据只在生产侧存在:分支保护与账本可信、
# 成本/配额真实记录与硬切断、CI/部署/回滚/HA/规模。
# 生产证据缺失时该表维记 None、总体 not_pass,绝不拉低代码表。
# - 产品表 PRODUCT_DIMENSION_IDS:沿用全部 7 维,但加一道真实
# 产品轮门禁(见 build_product_scorecard)。产品不是第 8 维,
# 也不是新指标:产品表 = “在真实产品轮里复测同一 7 维”。
# 没有真实产品轮证据时,产品表全部维记 None、总体 not_pass,
# 绝不把代码表/生产表的分数冒充成产品分数,也绝不声称
# 产品功能已落地。
#
# 独立性规则(与 build_scorecard 的旧规则一致,各表各自独立):
# - 每张表各自 overall 独立:本表全部维 >=9 才 pass,任一维
# <9 或 None 即 not_pass;average_score 只作参考,绝不作达标依据。
# - 代码表不含生产项:生产证据缺失、B/C 用户侧项 pending,
# 都不影响代码表的 overall(生产表才被挡住)。
# - 生产表与第 7 项 user_side_items 的配合是可选参数,不依赖
# 第 7 项的代码:调用方不传 user_side_items 时只按生产证据计分;
# 传了且其中有 pending 项时,生产表 overall 被强制 not_pass
# (维分数照常展示,不篡改),并在 missing_items 里逐项列出。
# - 阈值:三张表共用 DEFAULT_THRESHOLDS,默认值一律
# source="test_default_unapproved",未拍板;生产阈值须用户
# 拍板后由调用方显式传入 user_approved 阈值。
# ---------------------------------------------------------------------------
rubric_version:调用方显式传入的标尺版本号(见
cloud/scorecard_rubric.py)。本函数不查库、不定版本:
未传入时卡片记 rubric_version=None,表示“未锚定到版本化
标尺”,分数仍按 thresholds(或默认值)算出,但不具备
跨标尺可比性。计分规则、7 维定义、达标规则一字未改。
CODE_DIMENSION_IDS = [
"delivery_quality",
"gate_audit",
"arch_contract",
"test_coverage",
]
baseline_head:调用方显式传入的当前 main 头(机器字段,不是
docstring 里的文字说明)。不传入或传入空串时归一化为 None,
并在 missing_items 末尾记 baseline_head_missing;本函数绝不
编造、绝不探测版本控制状态。baseline 缺失本身不改写 overall
语义(overall 仍按 7 维算),漂移与否由 check_baseline_stale
单独判定,调用方不得只看 overall 就把旧分当现分用。
PRODUCTION_DIMENSION_IDS = [
"security_ledger",
"cost_quota",
"ops_scale",
]
evidence_rows(v7 机制第 4 项):调用方显式传入的证据行
列表(每行 dict),本函数只据此算 evidence_ledger_head 与
evidence_row_ids(见 compute_evidence_ledger),不写库、
不验签、不改变 overall。无证据行时 head 为 None、
row_ids 为空列表,不得编造。
"""
PRODUCT_DIMENSION_IDS = list(DIMENSION_IDS)
USER_SIDE_DONE_STATUSES = {
"done", "approved", "complete", "resolved", "user_approved",
}
PRODUCT_ROUND_REQUIRED_FIELDS = (
"real_product_round",
"real_app_installed",
"real_user_flow_verified",
"product_round_as_of",
)
def _build_table(dim_ids, evidence, th):
"""按给定维子集算一张表(纯函数;overall 与平均分规则同旧卡)。"""
evidence = evidence or {}
th = thresholds or {}
if baseline_head is not None and baseline_head == "":
baseline_head = None
ledger = compute_evidence_ledger(evidence_rows)
dimensions = []
missing_all, untested_all = [], []
for dim_id, _name in DIMENSIONS:
for dim_id in dim_ids:
result = _SCORERS[dim_id](evidence.get(dim_id) or {}, th)
dimensions.append(result)
missing_all.extend("%s: %s" % (dim_id, m) for m in result["missing_items"])
untested_all.extend("%s: %s" % (dim_id, u) for u in result["untested_items"])
if baseline_head is None:
missing_all.append("baseline_head_missing")
scores = [d["score"] for d in dimensions if d["score"] is not None]
average = _round1(sum(scores) / len(scores)) if scores else None
# 总体规则钉死:平均分绝不能作为达标依据。
# 钉死:平均分绝不能作为达标依据(各表各自独立判断)。
overall_pass = all(d["score"] is not None and d["score"] >= PASS_SCORE
for d in dimensions)
return {
@@ -654,14 +697,10 @@ def build_scorecard(evidence, thresholds=None, rubric_version=None,
"overall": "pass" if overall_pass else "not_pass",
"overall_pass": overall_pass,
"pass_score": PASS_SCORE,
"baseline_head": baseline_head,
"missing_items": missing_all,
"untested_items": untested_all,
"thresholds_source": thresholds_source(th),
"thresholds": _effective_thresholds(th),
"rubric_version": rubric_version,
"evidence_ledger_head": ledger["head"],
"evidence_row_ids": ledger["row_ids"],
}
@@ -711,7 +750,144 @@ def check_baseline_stale(scorecard, current_main_head):
"reason": reason,
"usable_as_pass_basis": not stale,
"overall_usable_as_pass_basis": not stale,
"overall_must_not_be_used_as_pass_basis": stale, }
"overall_must_not_be_used_as_pass_basis": stale,
}
def build_code_scorecard(evidence, thresholds=None):
"""代码表:仅 delivery_quality、gate_audit、arch_contract、test_coverage。
不含任何生产项;生产证据缺失、用户侧 B/C 项 pending 都不影响
本表 overall。本表全部 4 维 >=9 才 pass。
"""
return _build_table(CODE_DIMENSION_IDS, evidence, thresholds or {})
def _normalize_user_side_items(user_side_items):
"""把 user_side_items 占位证据归一化为 [{"id":..., "status":...}]。
接受:None(= 未提供,不臆断 pending)、dict{id: status}、
list[dict{id, status}]、list[str](字符串只有 id、无状态,
按 pending 计——状态未知绝不算 done)。
"""
if user_side_items is None:
return []
if isinstance(user_side_items, dict):
return [{"id": k, "status": v} for k, v in user_side_items.items()]
normalized = []
for item in user_side_items:
if isinstance(item, dict):
normalized.append({"id": item.get("id"),
"status": item.get("status")})
else:
normalized.append({"id": item, "status": "pending"})
return normalized
def build_production_scorecard(evidence, thresholds=None, user_side_items=None):
"""生产表:仅 security_ledger、cost_quota、ops_scale。
user_side_items 为可选占位证据(不依赖第 7 项的代码):
不传时只按生产证据计分;传了且有 pending 项时,维分数照常
展示,但 overall 被强制 not_pass,并在 missing_items 里逐项
列出 pending 项。生产证据缺失本身已使本表 not_pass。
"""
table = _build_table(PRODUCTION_DIMENSION_IDS, evidence, thresholds or {})
items = _normalize_user_side_items(user_side_items)
pending = [it for it in items
if it.get("status") not in USER_SIDE_DONE_STATUSES]
table["user_side_items"] = items
table["user_side_pending"] = pending
table["user_side_blocked"] = bool(pending)
if pending:
table["missing_items"] = list(table["missing_items"]) + [
"user_side_items_pending: %s" % it.get("id") for it in pending]
table["overall"] = "not_pass"
table["overall_pass"] = False
return table
def build_product_scorecard(evidence, thresholds=None, product_evidence=None):
"""产品表:全部 7 维,但须先过真实产品轮门禁。
product_evidence 须同时满足:real_product_round、real_app_installed、
real_user_flow_verified 均为真,且 product_round_as_of 非空。
门禁不过时,全部维记 None(unknown)、总体 not_pass,绝不把
代码表/生产表分数冒充成产品分数;本函数不声称任何产品功能已落地。
门禁通过时,7 维按与 build_scorecard 相同的 scorer 计分。
"""
product_evidence = product_evidence or {}
missing_fields = [f for f in PRODUCT_ROUND_REQUIRED_FIELDS
if not product_evidence.get(f)]
if missing_fields:
dimensions = []
missing_all = []
for dim_id in PRODUCT_DIMENSION_IDS:
missing = ["product_round_evidence_missing: %s" % f
for f in missing_fields]
dimensions.append(_result(dim_id, None, [], missing, []))
missing_all.extend("%s: %s" % (dim_id, m) for m in missing)
return {
"dimensions": dimensions,
"average_score": None,
"average_is_not_pass_criterion": True,
"overall": "not_pass",
"overall_pass": False,
"pass_score": PASS_SCORE,
"missing_items": missing_all,
"untested_items": [],
"thresholds_source": _thresholds_source(thresholds or {}),
"product_gate_passed": False,
"product_round_missing_fields": missing_fields,
}
table = _build_table(PRODUCT_DIMENSION_IDS, evidence, thresholds or {})
table["product_gate_passed"] = True
table["product_round"] = {
"real_product_round": True,
"real_app_installed": True,
"real_user_flow_verified": True,
"product_round_as_of": product_evidence.get("product_round_as_of"),
}
return table
def build_scorecard(evidence, thresholds=None, rubric_version=None,
baseline_head=None, evidence_rows=None,
user_side_items=None, product_evidence=None):
"""算出 7 维评分卡。evidence 缺键按空证据处理(该维记 None)。
兼容:旧返回字段(dimensions/average_score/overall 等)语义不变,
仅新增 code/production/product 三个子对象(见三张表拆分注释):
code=build_code_scorecard,production=build_production_scorecard
(user_side_items 可选占位),product=build_product_scorecard
(无真实产品轮证据时恒为 not_pass)。新增键不改变旧字段的值。
另新增 rubric_version(见 cloud/scorecard_rubric.py)、
baseline_head(机器字段,见 check_baseline_stale)、
evidence_ledger_head 与 evidence_row_ids(见
compute_evidence_ledger)三个机制字段;无证据行时头为 None。
"""
evidence = evidence or {}
th = thresholds or {}
if baseline_head is not None and baseline_head == "":
baseline_head = None
ledger = compute_evidence_ledger(evidence_rows)
report = _build_table(DIMENSION_IDS, evidence, th)
if baseline_head is None:
report["missing_items"] = list(report["missing_items"]) + [
"baseline_head_missing"]
report["baseline_head"] = baseline_head
report["rubric_version"] = rubric_version
report["evidence_ledger_head"] = ledger["head"]
report["evidence_row_ids"] = ledger["row_ids"]
report["thresholds"] = _effective_thresholds(th)
report["code"] = build_code_scorecard(evidence, thresholds)
report["production"] = build_production_scorecard(
evidence, thresholds, user_side_items)
report["product"] = build_product_scorecard(
evidence, thresholds, product_evidence)
return report
def example_scorecard_as_of_2026_10_31():
+23
View File
@@ -8592,6 +8592,9 @@ pid 须为整数、address 须为字符串,否则 400(注册表里的
证据传给 cloud/audit_scorecard.py 的 build_scorecard(),
端点本身绝不从测试文件、摘要文档、PR 描述里拼凑分数。
阈值仍为测试默认值(``test_default_unapproved``),未拍板。
响应同时带 ``code`` / ``production`` / ``product`` 三个子对象
(三张表拆分,见 cloud/audit_scorecard.py;示例证据下三表
均为 not_pass,产品表因无真实产品轮证据而恒 not_pass)。
"""
try:
from cloud.audit_scorecard import (
@@ -8608,6 +8611,26 @@ pid 须为整数、address 须为字符串,否则 400(注册表里的
"evidence_as_of": "2026-10-31",
"evidence_kind": "historical_example_snapshot",
"not_current_system_score": True,
# 三张表兜底形状:模块不可用时三表均为 not_pass。
"code": {"dimensions": [], "average_score": None,
"average_is_not_pass_criterion": True,
"overall": "not_pass", "overall_pass": False,
"missing_items": ["audit_scorecard_module_unavailable"],
"untested_items": []},
"production": {"dimensions": [], "average_score": None,
"average_is_not_pass_criterion": True,
"overall": "not_pass", "overall_pass": False,
"missing_items": ["audit_scorecard_module_unavailable"],
"untested_items": [],
"user_side_items": [],
"user_side_pending": [],
"user_side_blocked": False},
"product": {"dimensions": [], "average_score": None,
"average_is_not_pass_criterion": True,
"overall": "not_pass", "overall_pass": False,
"missing_items": ["audit_scorecard_module_unavailable"],
"untested_items": [],
"product_gate_passed": False},
}
self._send_json(200, report)
+294
View File
@@ -0,0 +1,294 @@
"""v7 机制第 2 项:三张表拆分定向测试。
维分配(与 cloud/audit_scorecard.py 的注释一致):
- 代码表:delivery_quality、gate_audit、arch_contract、test_coverage
(代码证据,不含生产项)。
- 生产表:security_ledger、cost_quota、ops_scale(生产证据)。
- 产品表:全部 7 维 + 真实产品轮门禁;无真实产品轮证据时恒 not_pass,
这只是评分卡输入结构拆分,不代表任何产品功能已落地。
钉住的规则:
- 代码表 overall 独立:生产证据缺失、B/C 用户侧项 pending,
都不拉低代码表。
- 生产表缺项不拉低代码表;生产表 overall 独立,平均分不作依据。
- 三张表各自 average_is_not_pass_criterion=True。
- 阈值默认值一律 test_default_unapproved,未拍板。
- 端点 GET /audit-scorecard 返回的示例卡带 code/production/product
三个子对象(端点已接线,非冒充)。
"""
import http.client
import json
import os
import sys
import tempfile
import threading
import unittest
from pathlib import Path
try:
from cloud.audit_scorecard import (
CODE_DIMENSION_IDS, DEFAULT_THRESHOLDS, PRODUCTION_DIMENSION_IDS,
PRODUCT_DIMENSION_IDS, build_code_scorecard,
build_product_scorecard, build_production_scorecard, build_scorecard,
example_scorecard_as_of_2026_10_31)
from cloud.auth import AuthStore
from cloud.server import create_server
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.audit_scorecard import (
CODE_DIMENSION_IDS, DEFAULT_THRESHOLDS, PRODUCTION_DIMENSION_IDS,
PRODUCT_DIMENSION_IDS, build_code_scorecard,
build_product_scorecard, build_production_scorecard, build_scorecard,
example_scorecard_as_of_2026_10_31)
from cloud.auth import AuthStore
from cloud.server import create_server
def _code_evidence():
return {
"delivery_quality": {
"first_pass_rate": 0.96, "defect_rate": 0.01,
"rework_rate": 0.04, "first_pass_known": True,
"defect_known": True, "rework_known": True,
"attempts_present": True, "evidence_kind": "real",
},
"gate_audit": {
"hard_gate_enforced": True, "gate_items_passed": 5,
"gate_items_total": 5, "merge_blocked_verified": True,
"loop_end_to_end_verified": True,
"sampling_misjudgment_rate": 0.0,
},
"arch_contract": {
"contract_frozen": True, "arch_violations": 0,
"directory_violations": 0, "import_violations": 0,
"stack_changed_without_approval": False,
},
"test_coverage": {
"prd_coverage_rate": 1.0, "cross_matrix_coverage_rate": 1.0,
"coverage_pct": 0.92, "cross_matrix_kind": "real",
"real_pg": True, "real_service": True,
"agent_six_complete": True,
"lint_items": 0, "mypy_items": 0, "bandit_high": 0,
},
}
def _production_evidence():
return {
"security_ledger": {
"ledger_verify_ok": True, "ledger_coverage_rate": 1.0,
"branch_protection": "protected",
"shell_whitelist_pass_rate": 1.0, "anchor_check_recent": True,
},
"cost_quota": {
"cost_records_complete": True, "unpriced_as_zero": False,
"per_creator_present": True, "quota_cutoff_verified": True,
},
"ops_scale": {
"ci_green_rate": 1.0, "deploy_success_rate": 1.0,
"rollback_drill_done": True, "ha_status": "second_host",
"parallel_scale_proven": 40,
},
}
def _full_evidence():
ev = {}
ev.update(_code_evidence())
ev.update(_production_evidence())
return ev
def _product_evidence():
return {
"real_product_round": True,
"real_app_installed": True,
"real_user_flow_verified": True,
"product_round_as_of": "2026-11-02",
}
class SplitTablesTestCase(unittest.TestCase):
def test_dimension_allocation_is_pinned(self):
self.assertEqual(CODE_DIMENSION_IDS, [
"delivery_quality", "gate_audit", "arch_contract",
"test_coverage"])
self.assertEqual(PRODUCTION_DIMENSION_IDS, [
"security_ledger", "cost_quota", "ops_scale"])
self.assertEqual(PRODUCT_DIMENSION_IDS, [
"delivery_quality", "gate_audit", "arch_contract",
"test_coverage", "security_ledger", "cost_quota", "ops_scale"])
self.assertFalse(set(CODE_DIMENSION_IDS)
& set(PRODUCTION_DIMENSION_IDS))
def test_code_table_passes_on_code_evidence_alone(self):
table = build_code_scorecard(_code_evidence())
self.assertEqual(table["overall"], "pass")
self.assertTrue(table["overall_pass"])
self.assertEqual([d["id"] for d in table["dimensions"]],
CODE_DIMENSION_IDS)
self.assertTrue(table["average_is_not_pass_criterion"])
self.assertEqual(table["thresholds_source"],
"test_default_unapproved")
for dim in table["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_bc_all_pending_code_passes_production_not_pass(self):
# 核心验收:B/C 全 pending 时代码表仍可 pass、生产表 not_pass。
# user_side_items 在此只是占位证据,不依赖第 7 项的代码。
user_side = [{"id": "B", "status": "pending"},
{"id": "C", "status": "pending"}]
code = build_code_scorecard(_full_evidence())
prod = build_production_scorecard(
_full_evidence(), user_side_items=user_side)
self.assertEqual(code["overall"], "pass")
self.assertEqual(prod["overall"], "not_pass")
self.assertFalse(prod["overall_pass"])
self.assertTrue(prod["user_side_blocked"])
self.assertEqual([p["id"] for p in prod["user_side_pending"]],
["B", "C"])
self.assertTrue(any("B" in m for m in prod["missing_items"]))
self.assertTrue(any("C" in m for m in prod["missing_items"]))
# 挡住 overall 但不篡改维分数:生产维本身仍全 >=9。
for dim in prod["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_bc_pending_in_dict_and_string_forms_also_blocks(self):
prod = build_production_scorecard(
_full_evidence(), user_side_items={"B": "pending"})
self.assertEqual(prod["overall"], "not_pass")
prod2 = build_production_scorecard(
_full_evidence(), user_side_items=["B"])
self.assertEqual(prod2["overall"], "not_pass")
def test_production_missing_evidence_does_not_lower_code_table(self):
# 生产证据直接缺失(不传 user_side_items 也一样):生产表
# not_pass,代码表仍 pass——缺项不跨表拉低。
code = build_code_scorecard(_code_evidence())
prod = build_production_scorecard(_code_evidence())
self.assertEqual(code["overall"], "pass")
self.assertEqual(prod["overall"], "not_pass")
for dim in prod["dimensions"]:
self.assertIsNone(dim["score"])
self.assertEqual(dim["status"], "unknown")
def test_production_passes_when_evidence_full_and_user_side_done(self):
prod = build_production_scorecard(
_full_evidence(),
user_side_items=[{"id": "B", "status": "done"},
{"id": "C", "status": "approved"}])
self.assertEqual(prod["overall"], "pass")
self.assertFalse(prod["user_side_blocked"])
self.assertEqual(prod["user_side_pending"], [])
def test_product_table_without_real_round_is_always_not_pass(self):
# 无真实产品轮证据:即使代码+生产证据全满,产品表也恒 not_pass,
# 全部维 None——绝不把代码/生产分数冒充成产品分数。
table = build_product_scorecard(_full_evidence())
self.assertEqual(table["overall"], "not_pass")
self.assertFalse(table["product_gate_passed"])
for dim in table["dimensions"]:
self.assertIsNone(dim["score"])
self.assertEqual(dim["status"], "unknown")
self.assertTrue(table["product_round_missing_fields"])
def test_product_table_with_real_round_scores_same_dimensions(self):
table = build_product_scorecard(_full_evidence(),
product_evidence=_product_evidence())
self.assertTrue(table["product_gate_passed"])
self.assertEqual(table["overall"], "pass")
self.assertEqual(len(table["dimensions"]), 7)
for dim in table["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_product_average_91_with_one_four_still_fails(self):
# 产品表平均分规则:6 维 10 分、1 维 4 分,平均 9.1,仍 not_pass。
ev = _full_evidence()
ev["gate_audit"]["hard_gate_enforced"] = False
table = build_product_scorecard(ev,
product_evidence=_product_evidence())
self.assertEqual(table["average_score"], 9.1)
self.assertTrue(table["average_is_not_pass_criterion"])
self.assertEqual(table["overall"], "not_pass")
def test_build_scorecard_carries_three_subobjects(self):
report = build_scorecard(
_full_evidence(),
user_side_items=[{"id": "B", "status": "pending"},
{"id": "C", "status": "pending"}])
# 旧字段语义不变:7 维全满时旧 overall 仍 pass。
self.assertEqual(report["overall"], "pass")
self.assertEqual(len(report["dimensions"]), 7)
self.assertEqual(report["code"]["overall"], "pass")
self.assertEqual(report["production"]["overall"], "not_pass")
# 产品表无真实产品轮证据,恒 not_pass。
self.assertEqual(report["product"]["overall"], "not_pass")
self.assertEqual([d["id"] for d in report["code"]["dimensions"]],
CODE_DIMENSION_IDS)
self.assertEqual(
[d["id"] for d in report["production"]["dimensions"]],
PRODUCTION_DIMENSION_IDS)
def test_example_card_carries_three_subobjects_all_not_pass(self):
report = example_scorecard_as_of_2026_10_31()
self.assertEqual(report["overall"], "not_pass")
self.assertEqual(report["code"]["overall"], "not_pass")
self.assertEqual(report["production"]["overall"], "not_pass")
self.assertEqual(report["product"]["overall"], "not_pass")
self.assertFalse(report["product"]["product_gate_passed"])
def test_threshold_defaults_still_unapproved_in_all_tables(self):
for entry in DEFAULT_THRESHOLDS.values():
self.assertEqual(entry["source"], "test_default_unapproved")
for table in (build_code_scorecard(_full_evidence()),
build_production_scorecard(_full_evidence()),
build_product_scorecard(_full_evidence(),
product_evidence=_product_evidence())):
self.assertEqual(table["thresholds_source"],
"test_default_unapproved")
class SplitTablesEndpointTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.db_path = os.path.join(self.tmp.name, "control.db")
self.auth = AuthStore(self.db_path)
self.owner_id, self.owner_key = self.auth.create_user("owner")
self.server = create_server(self.db_path, "127.0.0.1", 0)
self.port = self.server.server_address[1]
self.thread = threading.Thread(
target=self.server.serve_forever, daemon=True)
self.thread.start()
def tearDown(self):
self.server.shutdown()
self.server.server_close()
self.thread.join(timeout=5)
try:
self.auth.conn.close()
except Exception:
pass
self.tmp.cleanup()
def test_endpoint_returns_three_subobjects(self):
conn = http.client.HTTPConnection("127.0.0.1", self.port, timeout=10)
try:
conn.request("GET", "/audit-scorecard",
headers={"X-API-Key": self.owner_key})
resp = conn.getresponse()
report = json.loads(resp.read().decode("utf-8"))
finally:
conn.close()
self.assertEqual(resp.status, 200)
self.assertEqual(report["overall"], "not_pass")
for key in ("code", "production", "product"):
self.assertIn(key, report)
self.assertEqual(report[key]["overall"], "not_pass")
self.assertEqual(len(report["code"]["dimensions"]), 4)
self.assertEqual(len(report["production"]["dimensions"]), 3)
self.assertEqual(len(report["product"]["dimensions"]), 7)
if __name__ == "__main__":
unittest.main()