NAME

GDPR::IAB::TCFv2::Validator - declarative compliance checks for TC strings

SYNOPSIS

use GDPR::IAB::TCFv2::Validator;

my $validator = GDPR::IAB::TCFv2::Validator->new(
    vendor_id                       => 284,
    consent_purpose_ids             => [ 1, 3, 9 ],
    legitimate_interest_purpose_ids => [ 10 ],
    flexible_purpose_ids            => [ 10 ],
    verify_disclosed_vendors        => 1,
    min_tcf_policy_version          => 5,
    strict_legal_basis              => 1,
);

# Fail-fast: stops at the first failing rule.
my $tc_string = '...';
my $result = $validator->validate($tc_string);

# Accumulate every failure for richer error reporting.
$result = $validator->validate_all($tc_string);

if ($result) {
    # All rules passed.
}
else {
    warn "Compliance failed:\n$result\n";  # stringification = reasons
    for my $reason ( $result->reasons ) {
        warn "$reason";
    }
}

DESCRIPTION

GDPR::IAB::TCFv2::Validator is a small rule engine that turns a static "compliance policy" — required purposes, expected vendor, optional disclosed-vendors check — into a single validate / validate_all call against a TC string (or a pre-parsed GDPR::IAB::TCFv2 object).

Each rule produces a human-readable reason on failure; reasons are collected on a GDPR::IAB::TCFv2::Validator::Result object that overloads boolean and string contexts so it drops into typical error-handling idioms (if (!$result), print "$result\n") without ceremony.

CONSTRUCTOR

new

my $v = GDPR::IAB::TCFv2::Validator->new( %args );

Recognized keys:

  • vendor_id — the vendor whose access is being validated. Optional in the constructor (can be supplied per call via validate(..., vendor_id => N)) but one of the two must be set or validate/validate_all will croak with "missing vendor_id".

  • consent_purpose_ids — arrayref of purpose IDs that must have vendor consent. Validated via "is_vendor_consent_allowed" in GDPR::IAB::TCFv2.

  • legitimate_interest_purpose_ids — arrayref of purpose IDs that must have vendor legitimate-interest. Validated via "is_vendor_legitimate_interest_allowed" in GDPR::IAB::TCFv2. The IAB spec forbids LI for Purpose 1 always, and for Purposes 3-6 in TCF v2.2+; those are enforced by the underlying parser and surface here as failures.

  • flexible_purpose_ids — arrayref of purpose IDs that are flexible per the vendor's GVL declaration (the basis can flip if a publisher restriction is present in the TC string). The default basis is derived structurally from the other two lists:

    • If the purpose ID also appears in consent_purpose_ids, the default basis is consent.

    • If the purpose ID also appears in legitimate_interest_purpose_ids, the default basis is legitimate interest.

    A purpose listed in flexible_purpose_ids must also appear in exactly one of the other two lists, or the constructor croaks. Validated via "is_vendor_allowed_for_flexible_purpose" in GDPR::IAB::TCFv2.

  • verify_disclosed_vendors — boolean. When true, the validator inspects the TC string's Disclosed Vendors segment.

    If the segment is present, the vendor must appear there or the rule fails with "vendor N not disclosed" (ReasonVendorNotDisclosed).

    If the segment is absent, the behavior depends on the min_tcf_policy_version floor:

    • When min_tcf_policy_version is set to 5 or higher (TCF v2.3+), the segment is mandatory; absence causes a failure (ReasonMissingDisclosedVendors).

    • Otherwise (if min_tcf_policy_version is below 5 or unset), absence is silently ignored (matches legacy behavior).

  • strict_legal_basis — boolean. Passed through to the underlying is_vendor_*_allowed calls (as the strict named argument) so invalid purpose IDs cause croak instead of a silent failure. Defaults to 0.

METHODS

validate

my $result = $validator->validate( $tc_string_or_object, %overrides );

Runs the configured rules against $tc_string_or_object. Stops at the first failing rule (fail-fast mode) and returns a GDPR::IAB::TCFv2::Validator::Result carrying that one reason.

%overrides can replace the constructor values for vendor_id, strict_legal_basis, verify_disclosed_vendors, min_tcf_policy_version, cmp_validator, consent_purpose_ids, legitimate_interest_purpose_ids, and flexible_purpose_ids for this call only.

The list overrides (consent_purpose_ids, legitimate_interest_purpose_ids, flexible_purpose_ids) do not re-validate coherence — orphan entries (a flexible pid that isn't also in one of the basis lists) are silently dropped at runtime rather than fatal. This makes per-call overrides forgiving for callers that generate their lists dynamically; the constructor remains strict for the static policy.

$tc_string_or_object may be either a raw consent string or a pre-parsed GDPR::IAB::TCFv2 object — handy when the same TC string is being validated against multiple policies.

validate_all

Identical to "validate" but runs every rule and accumulates all failures into the result. Use when you want a complete error report rather than the first failure.

SEE ALSO

GDPR::IAB::TCFv2::Validator::Result for the result-object API, including the bool / "" overloads and the $\-aware stringification.

GDPR::IAB::TCFv2 for the underlying parser and the is_vendor_*_allowed family of methods this validator is built on.