Skip to content

Conversation

@jar-b
Copy link
Member

@jar-b jar-b commented Dec 5, 2025

Description

This function accepts a slice of any value and converts to a slice of UserAgentProduct structs. This functionality will be used by upstream clients which accept a list of raw string content to be appended to the User-Agent header, rather than a structured object with name, version, and comment sections explicitly defined.

For example, this convenience method allows the existing Context function to be used as follows.

        var metadata []string
        // other processing steps
        ctx = useragent.Context(ctx, useragent.FromSlice(metadata))

Relates hashicorp/terraform-provider-aws#45464

This function accepts a slice of any value and converts to a slice of `UserAgentProduct` structs. This functionality will be used by upstream clients which accept a list of raw string content to be appended to the User-Agent header, rather than a structured object with name, version, and comment sections explicitly defined.
@jar-b jar-b force-pushed the f-useragent-strings branch from 3566963 to c0aa19d Compare December 5, 2025 20:53
@jar-b jar-b marked this pull request as ready for review December 5, 2025 20:58
@jar-b jar-b requested a review from a team as a code owner December 5, 2025 20:58
YakDriver
YakDriver previously approved these changes Dec 5, 2025
Copy link
Member

@YakDriver YakDriver left a comment

Choose a reason for hiding this comment

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

LGTM 🎉

Couple minor nits

// pattern (where version and comment are optional) return a zero value struct.
func FromSlice[T any](sl []T) config.UserAgentProducts {
return slices.ApplyToAll(sl, func(v T) config.UserAgentProduct {
if s, ok := any(v).(string); ok && s != "" {
Copy link
Member

Choose a reason for hiding this comment

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

doesn't really need the empty check since fromString checks that?

return config.UserAgentProduct{Name: parts[0]}
case 2: //nolint: mnd
subparts := strings.Split(parts[1], "(")
if len(subparts) == 2 { //nolint: mnd
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if len(subparts) == 2 { //nolint: mnd
if len(subparts) == 2 && strings.HasSuffix(parts[1], ")") { //nolint: mnd

probably not worth "fixing" but an edge case "my-product/v1.2.3 (not a comment" that would parse wrong

Copy link
Member Author

Choose a reason for hiding this comment

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

A missing closing parenthesis would still parse correctly because strings.TrimSuffix(subparts[1], ")") just does nothing. For example, this test case passes.

		{
			"malformed comment closing",
			"my-product/v1.2.3 (a comment",
			config.UserAgentProduct{
				Name:    "my-product",
				Version: "v1.2.3",
				Comment: "a comment",
			},
		},
--- PASS: Test_fromString (0.00s)

    --- PASS: Test_fromString/malformed_comment_closing (0.00s)

There is weirdness if the opening parenthesis is missed because the version and comment will get mashed together into the Version struct field, but it winds up rendering the same in the eventual UA.

In general this conversion logic is just a shim until V2 of the AWSCC provider, where we'll deprecate the structured object user_agent in favor of a list of strings. At that time the shared components in this repo can also be simplified to just pass the strings through as-is without all this extra manipulation.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll still go ahead and add some test cases for malformed comment patterns, just so we document the edge cases exists and what the expected handling is.

Copy link
Collaborator

@ewbankkit ewbankkit left a comment

Choose a reason for hiding this comment

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

LGTM 🚀.

@jar-b jar-b merged commit 67e5766 into main Dec 8, 2025
13 checks passed
@jar-b jar-b deleted the f-useragent-strings branch December 8, 2025 15:48
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.

3 participants