135 config_ = std::make_unique<PolicyConfig>();
140 std::vector<std::string> lines = absl::StrSplit(yaml_content,
'\n');
141 bool in_policies =
false;
142 std::string current_policy_type;
143 std::string current_policy_name;
145 for (
const auto& line : lines) {
146 std::string trimmed = std::string(absl::StripAsciiWhitespace(line));
149 if (trimmed.empty() || trimmed[0] ==
'#')
153 if (absl::StartsWith(trimmed,
"version:")) {
154 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
155 if (parts.size() >= 2) {
156 config_->version = std::string(absl::StripAsciiWhitespace(parts[1]));
158 }
else if (absl::StartsWith(trimmed,
"enabled:")) {
159 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
160 if (parts.size() >= 2) {
161 std::string value = std::string(absl::StripAsciiWhitespace(parts[1]));
162 config_->enabled = (value ==
"true");
164 }
else if (trimmed ==
"policies:") {
166 }
else if (in_policies && absl::StartsWith(trimmed,
"- name:")) {
168 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
169 if (parts.size() >= 2) {
170 current_policy_name = std::string(absl::StripAsciiWhitespace(parts[1]));
172 }
else if (in_policies && absl::StartsWith(trimmed,
"type:")) {
173 std::vector<std::string> parts = absl::StrSplit(trimmed,
':');
174 if (parts.size() >= 2) {
175 current_policy_type = std::string(absl::StripAsciiWhitespace(parts[1]));
178 if (current_policy_type ==
"change_constraint") {
180 constraint.
name = current_policy_name;
183 constraint.
message =
"Change scope exceeded";
184 config_->change_constraints.push_back(constraint);
185 }
else if (current_policy_type ==
"forbidden_range") {
187 range.
name = current_policy_name;
188 range.
ranges.push_back(std::make_tuple(0xFFB0, 0xFFFF,
"ROM header"));
189 range.
message =
"Cannot modify protected region";
190 config_->forbidden_ranges.push_back(range);
191 }
else if (current_policy_type ==
"test_requirement") {
193 test.
name = current_policy_name;
194 test.
test_suites.push_back(std::make_pair(
"smoke_test", 1.0));
195 test.
message =
"Required tests must pass";
196 config_->test_requirements.push_back(test);
197 }
else if (current_policy_type ==
"review_requirement") {
199 review.
name = current_policy_name;
200 review.
message =
"Manual review required";
201 config_->review_requirements.push_back(review);
209 return absl::OkStatus();
213 return absl::OkStatus();
258 auto proposal_result = registry.GetProposal(std::string(proposal_id));
260 if (!proposal_result.ok()) {
264 const auto& proposal = proposal_result.value();
266 for (
const auto& policy :
config_->change_constraints) {
271 if (policy.max_bytes_changed > 0 &&
272 proposal.bytes_changed > policy.max_bytes_changed) {
275 violation.
severity = policy.severity;
277 absl::StrFormat(
"%s: %d bytes changed (limit: %d)", policy.message,
278 proposal.bytes_changed, policy.max_bytes_changed);
280 absl::StrFormat(
"Proposal changed %d bytes", proposal.bytes_changed);
285 if (policy.max_commands_executed > 0 &&
286 proposal.commands_executed > policy.max_commands_executed) {
289 violation.
severity = policy.severity;
290 violation.
message = absl::StrFormat(
291 "%s: %d commands executed (limit: %d)", policy.message,
292 proposal.commands_executed, policy.max_commands_executed);
293 violation.
details = absl::StrFormat(
"Proposal executed %d commands",
294 proposal.commands_executed);
316 auto proposal_result = registry.GetProposal(std::string(proposal_id));
318 if (!proposal_result.ok()) {
322 const auto& proposal = proposal_result.value();
324 for (
const auto& policy :
config_->review_requirements) {
329 for (
const auto& condition : policy.conditions) {
330 bool condition_met =
false;
333 if (absl::StrContains(condition.if_clause,
"bytes_changed")) {
335 if (absl::StrContains(condition.if_clause,
">")) {
336 std::vector<std::string> parts =
337 absl::StrSplit(condition.if_clause,
'>');
338 if (parts.size() == 2) {
340 if (absl::SimpleAtoi(absl::StripAsciiWhitespace(parts[1]),
342 condition_met = (proposal.bytes_changed > threshold);
346 }
else if (absl::StrContains(condition.if_clause,
"commands_executed")) {
347 if (absl::StrContains(condition.if_clause,
">")) {
348 std::vector<std::string> parts =
349 absl::StrSplit(condition.if_clause,
'>');
350 if (parts.size() == 2) {
352 if (absl::SimpleAtoi(absl::StripAsciiWhitespace(parts[1]),
354 condition_met = (proposal.commands_executed > threshold);
363 violation.
severity = policy.severity;
365 condition.message.empty() ? policy.message : condition.message;
367 absl::StrFormat(
"Condition met: %s → %s", condition.if_clause,
368 condition.then_clause);