124 config_ = std::make_unique<PolicyConfig>();
129 std::vector<std::string> lines = absl::StrSplit(yaml_content,
'\n');
130 bool in_policies =
false;
131 std::string current_policy_type;
132 std::string current_policy_name;
134 for (
const auto& line : lines) {
135 std::string trimmed = std::string(absl::StripAsciiWhitespace(line));
138 if (trimmed.empty() || trimmed[0] ==
'#')
continue;
141 if (absl::StartsWith(trimmed,
"version:")) {
142 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
143 if (parts.size() >= 2) {
144 config_->version = std::string(absl::StripAsciiWhitespace(parts[1]));
146 }
else if (absl::StartsWith(trimmed,
"enabled:")) {
147 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
148 if (parts.size() >= 2) {
149 std::string value = std::string(absl::StripAsciiWhitespace(parts[1]));
150 config_->enabled = (value ==
"true");
152 }
else if (trimmed ==
"policies:") {
154 }
else if (in_policies && absl::StartsWith(trimmed,
"- name:")) {
156 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
157 if (parts.size() >= 2) {
158 current_policy_name = std::string(absl::StripAsciiWhitespace(parts[1]));
160 }
else if (in_policies && absl::StartsWith(trimmed,
"type:")) {
161 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
162 if (parts.size() >= 2) {
163 current_policy_type = std::string(absl::StripAsciiWhitespace(parts[1]));
166 if (current_policy_type ==
"change_constraint") {
168 constraint.
name = current_policy_name;
171 constraint.
message =
"Change scope exceeded";
172 config_->change_constraints.push_back(constraint);
173 }
else if (current_policy_type ==
"forbidden_range") {
175 range.
name = current_policy_name;
177 std::make_tuple(0xFFB0, 0xFFFF,
"ROM header"));
178 range.
message =
"Cannot modify protected region";
179 config_->forbidden_ranges.push_back(range);
180 }
else if (current_policy_type ==
"test_requirement") {
182 test.
name = current_policy_name;
183 test.
test_suites.push_back(std::make_pair(
"smoke_test", 1.0));
184 test.
message =
"Required tests must pass";
185 config_->test_requirements.push_back(test);
186 }
else if (current_policy_type ==
"review_requirement") {
188 review.
name = current_policy_name;
189 review.
message =
"Manual review required";
190 config_->review_requirements.push_back(review);
198 return absl::OkStatus();
202 return absl::OkStatus();
246 auto proposal_result = registry.GetProposal(std::string(proposal_id));
248 if (!proposal_result.ok()) {
252 const auto& proposal = proposal_result.value();
254 for (
const auto& policy :
config_->change_constraints) {
255 if (!policy.enabled)
continue;
258 if (policy.max_bytes_changed > 0 &&
259 proposal.bytes_changed > policy.max_bytes_changed) {
262 violation.
severity = policy.severity;
263 violation.
message = absl::StrFormat(
264 "%s: %d bytes changed (limit: %d)", policy.message,
265 proposal.bytes_changed, policy.max_bytes_changed);
266 violation.
details = absl::StrFormat(
"Proposal changed %d bytes",
267 proposal.bytes_changed);
272 if (policy.max_commands_executed > 0 &&
273 proposal.commands_executed > policy.max_commands_executed) {
276 violation.
severity = policy.severity;
277 violation.
message = absl::StrFormat(
278 "%s: %d commands executed (limit: %d)", policy.message,
279 proposal.commands_executed, policy.max_commands_executed);
280 violation.
details = absl::StrFormat(
"Proposal executed %d commands",
281 proposal.commands_executed);
302 auto proposal_result = registry.GetProposal(std::string(proposal_id));
304 if (!proposal_result.ok()) {
308 const auto& proposal = proposal_result.value();
310 for (
const auto& policy :
config_->review_requirements) {
311 if (!policy.enabled)
continue;
314 for (
const auto& condition : policy.conditions) {
315 bool condition_met =
false;
318 if (absl::StrContains(condition.if_clause,
"bytes_changed")) {
320 if (absl::StrContains(condition.if_clause,
">")) {
321 std::vector<std::string> parts =
322 absl::StrSplit(condition.if_clause,
'>');
323 if (parts.size() == 2) {
325 if (absl::SimpleAtoi(absl::StripAsciiWhitespace(parts[1]),
327 condition_met = (proposal.bytes_changed > threshold);
331 }
else if (absl::StrContains(condition.if_clause,
"commands_executed")) {
332 if (absl::StrContains(condition.if_clause,
">")) {
333 std::vector<std::string> parts =
334 absl::StrSplit(condition.if_clause,
'>');
335 if (parts.size() == 2) {
337 if (absl::SimpleAtoi(absl::StripAsciiWhitespace(parts[1]),
339 condition_met = (proposal.commands_executed > threshold);
348 violation.
severity = policy.severity;
350 condition.message.empty() ? policy.message : condition.message;
351 violation.
details = absl::StrFormat(
352 "Condition met: %s → %s", condition.if_clause, condition.then_clause);