@maverickcer/env-cap
    Preparing search index...

    Function computeRotationStatus

    • Computes one variable's NIST SP 800-53 IA-5 rotation-compliance status from its lifecycle facts, relative to now.

      Parameters

      • variable: {
            authenticatorType: string | undefined;
            expiresAt: string | undefined;
            lastRotatedAt: string | undefined;
            rotationPeriod: string | undefined;
            rotationTriggerEvents: readonly string[] | undefined;
        }
      • now: Date

      Returns RotationComplianceStatus

      The judgment call this function makes (IA-5's main statement itself only says "change or refresh authenticators [by an organization-defined period] or when [organization-defined events] occur" -- it doesn't define how a pre-existing expiresAt and a new rotationPeriod/ lastRotatedAt pair should interact when both are declared on the same variable):

      • No rotation field declared at all (hasRotationData() false) -> "undeclared". Not an error -- most variables aren't authenticators, and saying nothing about rotation is the common, correct case, not a violation to report.
      • expiresAt is treated as authoritative and checked first, independent of everything else: if it's a valid date already in the past, the status is "expired", full stop. Rationale: expiresAt is a pre-existing, often externally-imposed hard deadline (an API key's own issuer-enforced expiry, a certificate's NotAfter) -- once that date passes, the value has literally stopped being valid, which is categorically worse than merely being overdue for an internal policy rotation, and no internal rotation record can retroactively un-expire it.
      • Otherwise, if rotationPeriod is declared, it's checked against lastRotatedAt: both present, both parseable (see parseRotationPeriodDays()), and lastRotatedAt no later than now -> compute lastRotatedAt + rotationPeriod and compare to now ("overdue" if that due date has passed, else "compliant"). Any other case with rotationPeriod declared -- lastRotatedAt missing, either value not statically parseable, or lastRotatedAt itself in the future (a rotation can't have happened yet, so trusting it would let a bad timestamp manufacture false compliance) -- fails closed to "overdue": IA-5 asks for evidence a rotation actually happened on schedule, and a declared obligation that can't be shown to have been met is reported as non-compliant rather than silently passed as compliant.
      • Otherwise (rotation metadata declared -- authenticatorType and/or lastRotatedAt and/or rotationTriggerEvents -- but no rotationPeriod and no past-due expiresAt) -> "compliant": nothing here states a time-based obligation this variable could be failing to meet.

      rotationTriggerEvents (the event-based trigger) deliberately never changes the returned status by itself: env-cap has no way to observe whether a listed event (a suspected compromise, a personnel change, ...) actually occurred, so treating its mere presence as either compliant or overdue would be fabricating a signal. It's presence-only evidence that the event-based half of IA-5's two-trigger model was at least declared -- a generator can and should still surface it, just never fold it into this computed status.