tgk1-edge: accept unknown hash ids and add regression test
This commit is contained in:
parent
5b7d07e033
commit
222fe2f84e
33
AUDITS.md
33
AUDITS.md
|
|
@ -38,8 +38,8 @@ Status legend: ✅ completed, ⬜ pending.
|
|||
10. ✅ `tier1/enc-pel1-result-1.md`
|
||||
11. ✅ `tier1/pel-trace-dag-1.md`
|
||||
12. ✅ `tier1/enc-pel-trace-dag-1.md`
|
||||
13. ⬜ `tier1/tgk-1-core.md`
|
||||
14. ⬜ `tier1/enc-tgk1-edge-1.md`
|
||||
13. ✅ `tier1/tgk-1-core.md`
|
||||
14. ✅ `tier1/enc-tgk1-edge-1.md`
|
||||
15. ⬜ `tier1/tgk-store-1.md`
|
||||
16. ⬜ `tier1/tgk-prov-1.md`
|
||||
17. ⬜ `tier1/opreg-pel1-kernel.md`
|
||||
|
|
@ -185,3 +185,32 @@ Status legend: ✅ completed, ⬜ pending.
|
|||
but permit unknown IDs and digest lengths, matching ENC/ASL1-CORE v1 behavior.
|
||||
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
|
||||
failed out of 14”).
|
||||
|
||||
## 2025-12-22 — TGK/1-CORE (`tier1/tgk-1-core.md`)
|
||||
- Scope: TGK/1-CORE EdgeArtifact recognition, EdgeBody invariants, profile
|
||||
configuration, and deterministic graph projection behavior in TGK stores.
|
||||
- Findings: `amduat_tgk_store_mem_init` does not validate
|
||||
`config.tgk_profiles.edge_tags`/`edge_tags_len` or
|
||||
`config.tgk_profiles.edge_types`/`edge_types_len`, so null pointers with
|
||||
non-zero lengths can lead to undefined behavior and prevent the required
|
||||
`EDGE_TAG_SET`/edge-type catalogs from being well-defined; no consistency
|
||||
checks ensure edge tags correspond to active edge encodings.
|
||||
- Resolution: added validation for edge tag/type list pointers and duplicates;
|
||||
enforced `TYPE_TAG_TGK1_EDGE_V1` presence when `TGK1_EDGE_ENC_V1` is active,
|
||||
and rejection when the encoding is inactive.
|
||||
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
|
||||
failed out of 14”).
|
||||
|
||||
## 2025-12-22 — ENC/TGK1-EDGE/1 (`tier1/enc-tgk1-edge-1.md`)
|
||||
- Scope: TGK1 EdgeBody encoding/decoding, EncodedRef framing, and profile
|
||||
invariants for `TGK1_EDGE_ENC_V1`.
|
||||
- Findings: `amduat_enc_tgk1_edge_encode_v1` rejects edges whose references use
|
||||
unknown (non-registry) `hash_id` values because it requires a
|
||||
registry-backed digest length when calculating `EncodedRef` sizes, which
|
||||
contradicts `ENC/ASL1-CORE v1.x` and §2.4’s requirement to accept unknown hash
|
||||
IDs with only reserved-ID rejection and length checks when known.
|
||||
- Resolution: updated `amduat_enc_tgk1_edge_encode_v1` sizing to allow unknown
|
||||
hash IDs per `ENC/ASL1-CORE`; added regression test for unknown `hash_id`
|
||||
edge references.
|
||||
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
|
||||
failed out of 14”).
|
||||
|
|
|
|||
|
|
@ -98,6 +98,46 @@ static bool amduat_tgk_store_mem_encoding_impl_supported(
|
|||
}
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_u32_list_has(const uint32_t *values,
|
||||
size_t len,
|
||||
uint32_t value) {
|
||||
size_t i;
|
||||
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
if (values == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (values[i] == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_u32_list_unique(const uint32_t *values,
|
||||
size_t len) {
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
if (values == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
for (j = i + 1; j < len; ++j) {
|
||||
if (values[i] == values[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amduat_tgk_store_mem_decode_profile(
|
||||
amduat_asl_encoding_profile_id_t profile_id,
|
||||
amduat_octets_t bytes,
|
||||
|
|
@ -1189,6 +1229,7 @@ bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
|
|||
size_t stored = 0;
|
||||
amduat_tgk_graph_edge_view_t *edges = NULL;
|
||||
size_t edges_len = 0;
|
||||
bool has_tgk1_encoding = false;
|
||||
|
||||
if (mem == NULL) {
|
||||
return false;
|
||||
|
|
@ -1208,9 +1249,46 @@ bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
|
|||
config.tgk_profiles.encodings == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (config.tgk_profiles.edge_tags_len != 0 &&
|
||||
config.tgk_profiles.edge_tags == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (config.tgk_profiles.edge_types_len != 0 &&
|
||||
config.tgk_profiles.edge_types == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_u32_list_unique(
|
||||
config.tgk_profiles.edge_tags,
|
||||
config.tgk_profiles.edge_tags_len)) {
|
||||
return false;
|
||||
}
|
||||
if (!amduat_tgk_store_mem_u32_list_unique(
|
||||
config.tgk_profiles.edge_types,
|
||||
config.tgk_profiles.edge_types_len)) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < config.tgk_profiles.encodings_len; ++i) {
|
||||
if (!amduat_tgk_store_mem_encoding_impl_supported(
|
||||
config.tgk_profiles.encodings[i])) {
|
||||
amduat_asl_encoding_profile_id_t profile_id =
|
||||
config.tgk_profiles.encodings[i];
|
||||
if (!amduat_tgk_store_mem_encoding_impl_supported(profile_id)) {
|
||||
return false;
|
||||
}
|
||||
if (profile_id == TGK1_EDGE_ENC_V1) {
|
||||
has_tgk1_encoding = true;
|
||||
}
|
||||
}
|
||||
if (has_tgk1_encoding) {
|
||||
if (!amduat_tgk_store_mem_u32_list_has(
|
||||
config.tgk_profiles.edge_tags,
|
||||
config.tgk_profiles.edge_tags_len,
|
||||
TYPE_TAG_TGK1_EDGE_V1)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (amduat_tgk_store_mem_u32_list_has(
|
||||
config.tgk_profiles.edge_tags,
|
||||
config.tgk_profiles.edge_tags_len,
|
||||
TYPE_TAG_TGK1_EDGE_V1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,16 +63,17 @@ static bool amduat_reference_bytes_len(amduat_reference_t ref, size_t *out_len)
|
|||
if (ref.digest.len != 0 && ref.digest.data == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (amduat_hash_asl1_is_reserved(ref.hash_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
desc = amduat_hash_asl1_desc_lookup(ref.hash_id);
|
||||
if (desc == NULL || desc->digest_len == 0) {
|
||||
return false;
|
||||
}
|
||||
if (ref.digest.len != desc->digest_len) {
|
||||
if (desc != NULL && desc->digest_len != 0 &&
|
||||
ref.digest.len != desc->digest_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_len = 2 + desc->digest_len;
|
||||
*out_len = 2 + ref.digest.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,11 +35,23 @@ static void fill_digest(uint8_t *out, uint8_t value) {
|
|||
memset(out, value, 32);
|
||||
}
|
||||
|
||||
static void fill_digest_len(uint8_t *out, size_t len, uint8_t value) {
|
||||
memset(out, value, len);
|
||||
}
|
||||
|
||||
static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) {
|
||||
fill_digest(storage, value);
|
||||
return amduat_reference(0x0001, amduat_octets(storage, 32));
|
||||
}
|
||||
|
||||
static amduat_reference_t make_ref_len(uint16_t hash_id,
|
||||
uint8_t value,
|
||||
uint8_t *storage,
|
||||
size_t len) {
|
||||
fill_digest_len(storage, len, value);
|
||||
return amduat_reference(hash_id, amduat_octets(storage, len));
|
||||
}
|
||||
|
||||
static bool bytes_equal(amduat_octets_t bytes,
|
||||
const uint8_t *expected,
|
||||
size_t expected_len) {
|
||||
|
|
@ -132,6 +144,55 @@ static int test_invalid_edge_version(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int test_unknown_hash_id_round_trip(void) {
|
||||
amduat_tgk_edge_body_t edge;
|
||||
amduat_reference_t from_refs[1];
|
||||
amduat_octets_t encoded;
|
||||
amduat_tgk_edge_body_t decoded;
|
||||
uint8_t f0[5];
|
||||
uint8_t p0[7];
|
||||
int exit_code = 1;
|
||||
|
||||
memset(&edge, 0, sizeof(edge));
|
||||
edge.type = 0x2b;
|
||||
|
||||
from_refs[0] = make_ref_len(0x1234, 0x44, f0, sizeof(f0));
|
||||
edge.from = from_refs;
|
||||
edge.from_len = 1;
|
||||
|
||||
edge.payload = make_ref_len(0x2345, 0x55, p0, sizeof(p0));
|
||||
|
||||
if (!amduat_enc_tgk1_edge_encode_v1(&edge, &encoded)) {
|
||||
fprintf(stderr, "encode failed for unknown hash_id\n");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
if (!amduat_enc_tgk1_edge_decode_v1(encoded, &decoded)) {
|
||||
fprintf(stderr, "decode failed for unknown hash_id\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (decoded.type != edge.type || decoded.from_len != 1 ||
|
||||
decoded.to_len != 0) {
|
||||
fprintf(stderr, "decoded field mismatch for unknown hash_id\n");
|
||||
goto cleanup_decoded;
|
||||
}
|
||||
|
||||
if (!amduat_reference_eq(decoded.from[0], edge.from[0]) ||
|
||||
!amduat_reference_eq(decoded.payload, edge.payload)) {
|
||||
fprintf(stderr, "decoded refs mismatch for unknown hash_id\n");
|
||||
goto cleanup_decoded;
|
||||
}
|
||||
|
||||
exit_code = 0;
|
||||
|
||||
cleanup_decoded:
|
||||
amduat_enc_tgk1_edge_free(&decoded);
|
||||
cleanup:
|
||||
free((void *)encoded.data);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int test_empty_endpoints(void) {
|
||||
amduat_tgk_edge_body_t edge;
|
||||
amduat_octets_t encoded;
|
||||
|
|
@ -184,6 +245,9 @@ int main(void) {
|
|||
if (test_invalid_edge_version() != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (test_unknown_hash_id_round_trip() != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (test_empty_endpoints() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,6 +346,92 @@ static int test_init_rejects_duplicate_hash_id(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int test_init_rejects_invalid_profile_config(void) {
|
||||
amduat_tgk_store_mem_t mem;
|
||||
amduat_tgk_store_config_t config;
|
||||
amduat_asl_encoding_profile_id_t encodings[1];
|
||||
uint32_t edge_tags[2];
|
||||
amduat_tgk_edge_type_id_t edge_types[2];
|
||||
|
||||
encodings[0] = TGK1_EDGE_ENC_V1;
|
||||
edge_tags[0] = TYPE_TAG_TGK1_EDGE_V1;
|
||||
edge_tags[1] = TYPE_TAG_TGK1_EDGE_V1;
|
||||
edge_types[0] = 0x10;
|
||||
edge_types[1] = 0x10;
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.encodings = encodings;
|
||||
config.tgk_profiles.encodings_len = 1;
|
||||
config.tgk_profiles.edge_tags_len = 1;
|
||||
config.tgk_profiles.edge_tags = NULL;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted null edge_tags\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.encodings = encodings;
|
||||
config.tgk_profiles.encodings_len = 1;
|
||||
config.tgk_profiles.edge_types_len = 1;
|
||||
config.tgk_profiles.edge_types = NULL;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted null edge_types\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.encodings = encodings;
|
||||
config.tgk_profiles.encodings_len = 1;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted encoding without edge tags\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.edge_tags = edge_tags;
|
||||
config.tgk_profiles.edge_tags_len = 1;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted edge tag without encoding\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.edge_tags = edge_tags;
|
||||
config.tgk_profiles.edge_tags_len = 2;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted duplicate edge tags\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mem, 0, sizeof(mem));
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.tgk_profiles.edge_types = edge_types;
|
||||
config.tgk_profiles.edge_types_len = 2;
|
||||
|
||||
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
|
||||
fprintf(stderr, "init accepted duplicate edge types\n");
|
||||
amduat_tgk_store_mem_free(&mem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_duplicate_edge_ref_same_artifact(void) {
|
||||
amduat_tgk_store_mem_t mem;
|
||||
amduat_tgk_store_t store;
|
||||
|
|
@ -1348,6 +1434,7 @@ int main(void) {
|
|||
test_resolve_edge_unsupported(&env) != 0 ||
|
||||
test_init_rejects_unsupported_encoding() != 0 ||
|
||||
test_init_rejects_duplicate_hash_id() != 0 ||
|
||||
test_init_rejects_invalid_profile_config() != 0 ||
|
||||
test_duplicate_edge_ref_same_artifact() != 0 ||
|
||||
test_duplicate_edge_ref_conflict() != 0 ||
|
||||
test_scan_edges_pagination() != 0 ||
|
||||
|
|
|
|||
Loading…
Reference in a new issue