Skip to content

[AAP-63312] Add workload_ttl_seconds field to WorkloadIdentityTokenRequestSerializer#952

Open
arrestle wants to merge 9 commits intoansible:develfrom
arrestle:aap63312_add_workload_ttl_to_serializer
Open

[AAP-63312] Add workload_ttl_seconds field to WorkloadIdentityTokenRequestSerializer#952
arrestle wants to merge 9 commits intoansible:develfrom
arrestle:aap63312_add_workload_ttl_to_serializer

Conversation

@arrestle
Copy link
Contributor

@arrestle arrestle commented Feb 24, 2026

[AAP-63312] Add workload_ttl_seconds field to WorkloadIdentityTokenRequestSerializer

Description

What is being changed?

Adding optional workload_ttl_seconds parameter to WorkloadIdentityTokenRequestSerializer to support workload-specific JWT TTL overrides.

Why is this change needed?

Gateway's AAP-63312 implementation requires the ability to accept workload-specific TTL values from API requests. This serializer change enables the API contract for that feature.

How does this change address the issue?

Adds a new optional IntegerField to the request serializer that validates TTL override values while maintaining backward compatibility (field is optional).

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Test update

Self-Review Checklist

  • I have performed a self-review of my code
  • I have added relevant comments to complex code sections
  • I have updated documentation where needed
  • I have considered the security impact of these changes
  • I have considered performance implications
  • I have thought about error handling and edge cases
  • I have tested the changes in my local environment

Implementation

Modified: ansible_base/lib/workload_identity/workload_identity_tokens.py (11 lines)
Modified: test_app/tests/lib/workload_identity/test_serializers.py (86 lines)

Added optional workload_ttl_seconds field with validation (min_value=0, allow_null, not required).

Testing Instructions

# Run serializer tests
tox -e py -- test_app/tests/lib/workload_identity/test_serializers.py -v

Expected: 29 tests pass (22 existing + 7 new)

Additional Context

Backward compatible: Field is optional, existing requests work unchanged.

Requires coordinated Gateway PR to implement TTL calculation logic.

Related: AAP-63296 (P4.1), ANSTRAT-1019


Development Note: This implementation was developed with assistance from Claude AI assistant.

https://handbook.eng.ansible.com/proposals/ANSTRAT-1019-Configurable-JWT-Expiration-for-OIDC-Integrations

Assisted-by: Claude

Summary by CodeRabbit

  • New Features

    • Optional workload_ttl_seconds parameter to request per-workload token TTL overrides (nullable or omitted to use platform default); accepts a positive integer up to a 24-hour ceiling and applies an automatic 60s clock-skew buffer.
  • Tests

    • Comprehensive tests covering valid value, zero (rejected), null, omission, negative, exceeding max, and non‑integer inputs to verify behavior and error messages.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a hard cap constant and an optional, nullable workload_ttl_seconds IntegerField to WorkloadIdentityTokenRequestSerializer, and introduces tests covering valid, boundary, null/omitted, and invalid inputs.

Changes

Cohort / File(s) Summary
Serializer & constant
ansible_base/lib/workload_identity/workload_identity_tokens.py
Added WORKLOAD_TTL_MAX_SECONDS = 24 * 60 * 60 and added an optional, nullable workload_ttl_seconds IntegerField on WorkloadIdentityTokenRequestSerializer with min_value=1, max_value=get_setting('ANSIBLE_BASE_WIT_MAX_TOKEN_TTL', WORKLOAD_TTL_MAX_SECONDS) (exposed as WORKLOAD_TTL_MAX_SECONDS in tests), and expanded help_text describing per-workload override, platform fallback when omitted/null, and an automatic 60s JWT clock skew.
Tests
test_app/tests/lib/workload_identity/test_serializers.py
Added seven tests validating workload_ttl_seconds behavior: valid value preserved, zero fails (min_value), null accepted, omitted accepted (optional), negative fails, exceeding max fails, and non-integer fails; imports WORKLOAD_TTL_MAX_SECONDS for max checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a new workload_ttl_seconds field to the WorkloadIdentityTokenRequestSerializer, which matches the core objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@arrestle arrestle changed the title Add workload_ttl_seconds field to WorkloadIdentityTokenRequestSerializer [AAP-63312] Add workload_ttl_seconds field to WorkloadIdentityTokenRequestSerializer Feb 24, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ansible_base/lib/workload_identity/workload_identity_tokens.py`:
- Around line 28-38: The IntegerField workload_ttl_seconds currently has no
upper bound; add a max_value to the serializers.IntegerField (e.g.,
max_value=settings.JWT_MAX_TTL_SECONDS or max_value=jwt_default_ttl_seconds) to
prevent arbitrarily large TTLs, update the help_text to document the maximum,
and ensure any referenced constant (JWT_MAX_TTL_SECONDS/jwt_default_ttl_seconds)
is imported or available where workload_ttl_seconds is defined so validation
uses the intended platform maximum.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 898bb77 and 83bfbb7.

📒 Files selected for processing (2)
  • ansible_base/lib/workload_identity/workload_identity_tokens.py
  • test_app/tests/lib/workload_identity/test_serializers.py

Copy link
Member

@john-westcott-iv john-westcott-iv left a comment

Choose a reason for hiding this comment

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

Code Review Summary

Clean serializer addition — the field definition is well-structured with proper optionality and the test coverage hits all the boundary cases (valid, zero, null, omitted, negative, non-integer).

Files Reviewed: 2 files
Comments Posted: 1 reply to existing thread

Issues Found

  • 1 security suggestion (no max_value — reinforced existing thread with additional context)
  • 0 correctness/logic issues
  • 0 code quality suggestions

Overall Assessment

LGTM with the max_value addition. Replied to the existing thread with +1 and rationale — a configurable max conforms to "no hard maximum" while preventing effectively infinite token lifetimes (a known complaint from our OAuth token experience).

General Feedback

  • Test assertions on error codes (min_value, invalid) are a nice touch
  • allow_null=True + required=False combination correctly handles both omission and explicit null

Copy link
Contributor

@dleehr dleehr left a comment

Choose a reason for hiding this comment

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

Nice use of the serializer min_value to let validation handle this. Requesting changes around the special-casing of 0 (also noted in the other PR) and pending a decision on the max_value

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test_app/tests/lib/workload_identity/test_serializers.py (1)

222-323: Consider adding exact boundary pass-tests for min_value=1 and max_value=WORKLOAD_TTL_MAX_SECONDS.

The suite confirms that 0 and max+1 fail, but doesn't verify that 1 and WORKLOAD_TTL_MAX_SECONDS themselves are accepted. A future change to the constraints would silently break those boundaries without a test catching it.

➕ Suggested additions
def test_workload_ttl_seconds_min_boundary_passes(self):
    data = {
        'scope': 'openid',
        'audience': 'https://api.example.com',
        'claims': {'job_name': 'test-job'},
        'workload_ttl_seconds': 1,
    }
    serializer = WorkloadIdentityTokenRequestSerializer(data=data)
    assert serializer.is_valid(), f"Serializer errors: {serializer.errors}"
    assert serializer.validated_data['workload_ttl_seconds'] == 1

def test_workload_ttl_seconds_max_boundary_passes(self):
    data = {
        'scope': 'openid',
        'audience': 'https://api.example.com',
        'claims': {'job_name': 'test-job'},
        'workload_ttl_seconds': WORKLOAD_TTL_MAX_SECONDS,
    }
    serializer = WorkloadIdentityTokenRequestSerializer(data=data)
    assert serializer.is_valid(), f"Serializer errors: {serializer.errors}"
    assert serializer.validated_data['workload_ttl_seconds'] == WORKLOAD_TTL_MAX_SECONDS
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test_app/tests/lib/workload_identity/test_serializers.py` around lines 222 -
323, Add two boundary tests to assert the inclusive min and max are accepted:
implement test_workload_ttl_seconds_min_boundary_passes and
test_workload_ttl_seconds_max_boundary_passes that each construct a payload with
workload_ttl_seconds set to 1 and WORKLOAD_TTL_MAX_SECONDS respectively,
instantiate WorkloadIdentityTokenRequestSerializer with that data, assert
serializer.is_valid() and that serializer.validated_data['workload_ttl_seconds']
equals the provided value; place them alongside the existing
workload_ttl_seconds tests so future changes to the min_value=1 and
max_value=WORKLOAD_TTL_MAX_SECONDS constraints are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ansible_base/lib/workload_identity/workload_identity_tokens.py`:
- Around line 42-47: The help_text uses an EN DASH and an f-string inside the
gettext_lazy call which breaks extraction; change the en-dash to a plain hyphen
and remove the f-string by making the translatable string a plain literal (e.g.
assign a template string constant like HELP_TEXT_TTL = "Optional
workload-specific TTL override in seconds (1-{max}). If provided, ..." and then
call _(HELP_TEXT_TTL).format(max=WORKLOAD_TTL_MAX_SECONDS)) so that _('...')
contains no f-string; update the help_text assignment that references
WORKLOAD_TTL_MAX_SECONDS and use the .format(...) approach (or inline the
numeric constant) to keep gettext_extractable.

---

Nitpick comments:
In `@test_app/tests/lib/workload_identity/test_serializers.py`:
- Around line 222-323: Add two boundary tests to assert the inclusive min and
max are accepted: implement test_workload_ttl_seconds_min_boundary_passes and
test_workload_ttl_seconds_max_boundary_passes that each construct a payload with
workload_ttl_seconds set to 1 and WORKLOAD_TTL_MAX_SECONDS respectively,
instantiate WorkloadIdentityTokenRequestSerializer with that data, assert
serializer.is_valid() and that serializer.validated_data['workload_ttl_seconds']
equals the provided value; place them alongside the existing
workload_ttl_seconds tests so future changes to the min_value=1 and
max_value=WORKLOAD_TTL_MAX_SECONDS constraints are caught.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 83bfbb7 and afc8f49.

📒 Files selected for processing (2)
  • ansible_base/lib/workload_identity/workload_identity_tokens.py
  • test_app/tests/lib/workload_identity/test_serializers.py

Copy link
Contributor

@dleehr dleehr left a comment

Choose a reason for hiding this comment

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

Looks good, but the terraform-related comments lack context and may be confusing. Please remove those.

Addressed dleehr review: external vendor references add no value
in this context and may be confusing.

Made-with: Cursor
Copy link

@dragid10 dragid10 left a comment

Choose a reason for hiding this comment

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

(as DAB rep)
Overall looks good
Low Care Amount: I see there is a test for not an integer (tests with a string). I'd imagine a float would also be rejected? Do we need a test to check it doesn't slip through via truncation or something?

@dleehr dleehr requested a review from matoval February 26, 2026 15:54
Copy link
Member

@john-westcott-iv john-westcott-iv left a comment

Choose a reason for hiding this comment

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

Code Review Summary

Clean serializer addition with all prior review feedback addressed. The field definition, optionality handling (allow_null=True + required=False), and test coverage are solid.

Files Reviewed: 2 files
Comments Posted: 3 inline suggestions

Issues Found

  • 0 security/correctness issues
  • 3 minor quality suggestions (all non-blocking)

Overall Assessment

LGTM — approving with minor suggestions:

  1. Consider using get_setting() for max_value to enable per-service configurability (established DAB pattern)
  2. Drop the hardcoded range (1-86400) from help_text to match DAB conventions and avoid staleness
  3. Parameterize the invalid-value tests and add a float case per @dleehr and @dragid10's discussion

Note: This review was submitted with assistance from Claude AI assistant on behalf of John Westcott.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ansible_base/lib/workload_identity/workload_identity_tokens.py`:
- Around line 33-37: The code references get_setting in the workload_ttl_seconds
field but does not import it, causing a NameError at import time; add an import
for get_setting at the top of the module (e.g. from ansible_base.settings import
get_setting) so workload_ttl_seconds can call get_setting(...,
WORKLOAD_TTL_MAX_SECONDS) without failing.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 770ade1 and 942d3c4.

📒 Files selected for processing (1)
  • ansible_base/lib/workload_identity/workload_identity_tokens.py

Copy link

@davemulford davemulford left a comment

Choose a reason for hiding this comment

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

Changes look good. I see there is a failing test but that's happening outside of the changes you've made, and you're following up with the django-ansible-base team about that.

@github-actions
Copy link

DVCS PR Check Results:

PR appears valid (JIRA key(s) found)

@sonarqubecloud
Copy link

Copy link
Contributor

@dleehr dleehr left a comment

Choose a reason for hiding this comment

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

I'm requesting changes to block this merge for now.

The most recent commits modify the validation logic that was approved and are now using custom logic and a previously-unused class. I need to understand that better before merging.

@arrestle
Copy link
Contributor Author

Nice use of the serializer min_value to let validation handle this. Requesting changes around the special-casing of 0 (also noted in the other PR) and pending a decision on the max_value

The validation logic changed because max_value=get_setting(...) on the field was evaluated at class definition time and caused pure-python-imports to fail (Django settings aren’t available at import time).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants