Skip to content

mgmt/rpc: refuse RECA_READ_ONLY/RECA_NO_ACCESS writes#13142

Draft
brbzull0 wants to merge 1 commit intoapache:masterfrom
brbzull0:mgmt_record_set_honor_access_type
Draft

mgmt/rpc: refuse RECA_READ_ONLY/RECA_NO_ACCESS writes#13142
brbzull0 wants to merge 1 commit intoapache:masterfrom
brbzull0:mgmt_record_set_honor_access_type

Conversation

@brbzull0
Copy link
Copy Markdown
Contributor

@brbzull0 brbzull0 commented May 7, 2026

set_config_records did not consult the registrant's access tier, so admin_config_set_records (and traffic_ctl config set) accepted writes to records the registrant marked as protected. Read the record's access_type alongside the existing metadata, and refuse the write with an specific error code (RECORD_READ_ONLY / RECORD_NO_ACCESS)

follow-up of #13141

set_config_records did not consult the registrant's access tier,
so admin_config_set_records (and "traffic_ctl config set") accepted
writes to records the registrant marked as protected.  Read the
record's access_type alongside the existing metadata, and refuse
the write with an specific error code (RECORD_READ_ONLY /
RECORD_NO_ACCESS)
@brbzull0 brbzull0 self-assigned this May 7, 2026
@brbzull0 brbzull0 added the Records Records related code. label May 7, 2026
@brbzull0 brbzull0 requested a review from Copilot May 7, 2026 13:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens management-plane record mutation semantics by ensuring admin_config_set_records / traffic_ctl config set refuses writes to configuration records that were registered as protected via RecAccessT (e.g., RECA_READ_ONLY, RECA_NO_ACCESS), aligning write behavior with record registration intent.

Changes:

  • Read config_meta.access_type during record lookup in set_config_records() and reject protected writes.
  • Add new record-specific error identifiers/messages (RECORD_READ_ONLY, RECORD_NO_ACCESS) to the RPC record error category.
  • Add a gold test that attempts (and expects) a rejected write to a known RECA_READ_ONLY config record.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/mgmt/rpc/handlers/config/Configuration.cc Adds access-tier enforcement to config record writes and returns an error on protected records.
src/mgmt/rpc/handlers/common/RecordsUtils.h Extends RecordError with RECORD_READ_ONLY / RECORD_NO_ACCESS.
src/mgmt/rpc/handlers/common/RecordsUtils.cc Provides human-readable messages for the new RecordError values.
tests/gold_tests/traffic_ctl/traffic_ctl_set_read_only.test.py New integration test validating RECA_READ_ONLY records can’t be modified via the management RPC.

Comment on lines 135 to +150
LookupContext recordCtx;
std::get<RecAccessT>(recordCtx) = RECA_NULL;

// Get record info first. TODO: we may just want to get the full record and then send it back as a response.
const auto ret = RecLookupRecord(
info.name.c_str(),
[](const RecRecord *record, void *data) {
auto &[dataType, checkType, pattern, updateType] = *static_cast<LookupContext *>(data);
auto &[dataType, checkType, pattern, updateType, accessType] = *static_cast<LookupContext *>(data);
if (REC_TYPE_IS_CONFIG(record->rec_type)) {
dataType = record->data_type;
checkType = record->config_meta.check_type;
if (record->config_meta.check_expr) {
pattern = record->config_meta.check_expr;
}
updateType = record->config_meta.update_type;
accessType = record->config_meta.access_type;
Comment on lines +169 to +173
if (accessType == RECA_READ_ONLY || accessType == RECA_NO_ACCESS) {
auto const ec =
std::error_code{accessType == RECA_READ_ONLY ? err::RecordError::RECORD_READ_ONLY : err::RecordError::RECORD_NO_ACCESS};
resp.errata().assign(std::error_code{errors::Codes::RECORD}).note("{}", ec);
continue;
Comment on lines +70 to +77
def assert_set_was_rejected(resp: Response):
"""Validate the set attempt produced the not-writable error."""
if not resp.is_error():
return (False, f"set should have failed but returned a result: {resp.result!r}")
err = resp.error_as_str()
if "Record is read-only" not in err:
return (False, f"unexpected error message: {err!r}")
return (True, "set was refused with RECORD_READ_ONLY")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Records Records related code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants