Skip to content

[FEATURE] update ACL Token Read endpoint to add expanded parameter#601

Merged
marcin-krystianc merged 16 commits intoG-Research:masterfrom
MohamedM216:acl-token-read
Mar 24, 2026
Merged

[FEATURE] update ACL Token Read endpoint to add expanded parameter#601
marcin-krystianc merged 16 commits intoG-Research:masterfrom
MohamedM216:acl-token-read

Conversation

@MohamedM216
Copy link
Copy Markdown
Contributor

@MohamedM216 MohamedM216 commented Mar 10, 2026

Description

update ACL Token Read endpoint to add expnded parameter

Related Issues

#531

Additional Context

Checklist

Please make sure to check the following before submitting your pull request:

  • Did you read the contributing guidelines?
  • Did you update the docs?
  • Did you write any tests to validate this change?

Copy link
Copy Markdown
Contributor

@marcin-krystianc marcin-krystianc left a comment

Choose a reason for hiding this comment

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

HI @MohamedM216,

look at the example of a response when the expanded=true (https://developer.hashicorp.com/consul/api-docs/acl/tokens#sample-response-1). See, there are two new fields, ExpandedPolicies and ExpandedRoles.
The test should assert that these fields are filled in, when expanded=true and null when expanded=false.

@MohamedM216
Copy link
Copy Markdown
Contributor Author

ExpandedPolicies and ExpandedRoles don't exist in QueryResult<TokenEntry> or PolicyLink. PolicyLink only has ID and Name. Any ideas?

Comment thread Consul/Token.cs Outdated
Comment on lines +108 to +122
public TokenEntry(string accessorId, string description, PolicyLink[] policies, RoleLink[] roles, ServiceIdentity[] serviceIdentities, ExpandedPolicy[] expandedPolicies, ExpandedRole[] expandedRoles, string[] namespaceDefaultPolicyIDs, string[] namespaceDefaultRoleIDs, string agentACLDefaultPolicy, string agentACLDownPolicy, string resolvedByAgent)
{
AccessorID = accessorId;
Description = description;
Policies = policies;
Roles = roles;
ServiceIdentities = serviceIdentities;
ExpandedPolicies = expandedPolicies;
ExpandedRoles = expandedRoles;
NamespaceDefaultPolicyIDs = namespaceDefaultPolicyIDs;
NamespaceDefaultRoleIDs = namespaceDefaultRoleIDs;
AgentACLDefaultPolicy = agentACLDefaultPolicy;
AgentACLDownPolicy = agentACLDownPolicy;
ResolvedByAgent = resolvedByAgent;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we need to add this constructor? It just adds noise to the codebase.

Comment thread Consul/ExpandedRole.cs Outdated
Comment on lines +29 to +37
public ExpandedRole(string id, string name, string description, PolicyLink[] policies, ServiceIdentity[] serviceIdentities)
{
ID = id;
Name = name;
Description = description;
Policies = policies;
ServiceIdentities = serviceIdentities;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we need to add this constructor? It just adds noise to the codebase.

Comment thread Consul/ExpandedPolicy.cs Outdated
Comment on lines +31 to +38
public ExpandedPolicy(string id, string name, string description, string rules, string[] datacenters)
{
ID = id;
Name = name;
Description = description;
Rules = rules;
Datacenters = datacenters;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we need to add this constructor? It just adds noise to the codebase.

Comment thread Consul.Test/TokenTest.cs Outdated
// create test policy
var policyEntry = new PolicyEntry
{
Name = "TestExpandedPolicy-" + Guid.NewGuid().ToString().Substring(0, 8),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please use KVTest.GenerateTestKeyName() for generating random names (we want to have a consistent way of generating random names).

Comment thread Consul/ExpandedPolicy.cs Outdated
// </copyright>
// -----------------------------------------------------------------------

using System.Data;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it is not used, please remove:

Suggested change
using System.Data;

Copy link
Copy Markdown
Contributor

@marcin-krystianc marcin-krystianc left a comment

Choose a reason for hiding this comment

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

Please improve assertions where applicable (e.g. Assert.NotEmpty instead of Assert.NotNull)

Comment thread Consul.Test/TokenTest.cs Outdated
// when expanded=false
var unexpandedRead = await _client.Token.Read(accessorId, false, QueryOptions.Default);
Assert.NotNull(unexpandedRead.Response.Policies);
Assert.Equal(unexpandedRead.Response.Policies.FirstOrDefault().Name, policyEntry.Name);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

xUnit convention is Assert.Equal(expected, actual):

Suggested change
Assert.Equal(unexpandedRead.Response.Policies.FirstOrDefault().Name, policyEntry.Name);
Assert.Equal(policyEntry.Name, unexpandedRead.Response.Policies.FirstOrDefault().Name);

Comment thread Consul.Test/TokenTest.cs Outdated
Assert.NotNull(expandedRead.Response.AgentACLDownPolicy);
Assert.NotNull(expandedRead.Response.ResolvedByAgent);
Assert.NotNull(expandedRead.Response.ExpandedPolicies);
Assert.Equal(expandedRead.Response.ExpandedPolicies.FirstOrDefault().Rules, policyEntry.Rules);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

` xUnit convention is Assert.Equal(expected, actual):

  • No need to use the FirstOrDefault() form (it would throw confusing exception, it ExpandedPolicies was empty)
Suggested change
Assert.Equal(expandedRead.Response.ExpandedPolicies.FirstOrDefault().Rules, policyEntry.Rules);
Assert.Equal(policyEntry.Rules, expandedRead.Response.ExpandedPolicies.First().Rules);

Comment thread Consul.Test/TokenTest.cs Outdated
Assert.NotNull(expandedRead.Response.ExpandedPolicies);
Assert.Equal(expandedRead.Response.ExpandedPolicies.FirstOrDefault().Rules, policyEntry.Rules);
Assert.NotNull(expandedRead.Response.ExpandedRoles);
Assert.Equal(expandedRead.Response.ExpandedRoles.FirstOrDefault().Name, roleEntry.Name);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

xUnit convention is Assert.Equal(expected, actual):

Suggested change
Assert.Equal(expandedRead.Response.ExpandedRoles.FirstOrDefault().Name, roleEntry.Name);
Assert.Equal(roleEntry.Name, expandedRead.Response.ExpandedRoles.FirstOrDefault().Name);

Comment thread Consul.Test/TokenTest.cs Outdated
Assert.NotNull(expandedRead.Response.AgentACLDefaultPolicy);
Assert.NotNull(expandedRead.Response.AgentACLDownPolicy);
Assert.NotNull(expandedRead.Response.ResolvedByAgent);
Assert.NotNull(expandedRead.Response.ExpandedPolicies);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Slightly better (stricter) check:

Suggested change
Assert.NotNull(expandedRead.Response.ExpandedPolicies);
Assert.NotEmpty(expandedRead.Response.ExpandedPolicies);

Comment thread Consul.Test/TokenTest.cs Outdated
public async Task Token_ReadExpanded()
{
var cutOffVersion = SemanticVersion.Parse("1.12.0");
Skip.If(AgentVersion < cutOffVersion, $"Current version is {AgentVersion}, but `Namespaces` is only supported from Consul {cutOffVersion}");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Error message is not accurate, please update it.

- improve assertions: use Assert.NotEmpty instead of Assert.NotNull
- better consul versions exclusion message
Copy link
Copy Markdown
Contributor

@marcin-krystianc marcin-krystianc 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 now, thank you!

Task<WriteResult<bool>> Delete(string id, WriteOptions q, CancellationToken ct = default);
Task<QueryResult<TokenEntry>> Read(string id, CancellationToken ct);
Task<QueryResult<TokenEntry>> Read(string id);
Task<QueryResult<TokenEntry>> Read(string id, QueryOptions q, CancellationToken ct = default);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Due to losing this API, now during the building process, we get this:

/home/mohammad/programs/mlh-fellowship/projects/consuldotnet/consuldotnet/Consul/PublicAPI/PublicAPI.Shipped.txt(3013,1): error RS0017: Symbol 'Consul.ITokenEndpoint.Read(string id, Consul.QueryOptions q, System.Threading.CancellationToken ct = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Consul.QueryResult<Consul.TokenEntry>>' is part of the declared API, but is either not public or could not be found (https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
    /home/mohammad/programs/mlh-fellowship/projects/consuldotnet/consuldotnet/Consul/PublicAPI/PublicAPI.Shipped.txt(4099,1): error RS0017: Symbol 'Consul.Token.Read(string id, Consul.QueryOptions queryOptions, System.Threading.CancellationToken ct = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Consul.QueryResult<Consul.TokenEntry>>' is part of the declared API, but is either not public or could not be found (https://github.com/dotnet/roslyn-analyzers/blob/main/src/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)

It's a breaking change and we should keep it in Shipped.txt. So the only way I see is to add the expanded parameter to QueryOptions, although QueryOptions is generic and expanded does only belong to ACL token Read endpoints, then we won't have any breaking changes and won't have to add any new overloads as well?
Also it's good to mention that we will face the same issue in #592

Please let me know your thoughts.
Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See here how to handle this (dotnet/roslyn-analyzers#5058):

You should copy the entry for your change from PublicAPI.Shipped.txt and then put that entry in PublicAPI.Unshipped.txt with REMOVED prefix.

Comment thread Consul.Test/TokenTest.cs Outdated
Comment on lines +368 to +373
var list = await _client.Token.List();
var testToken = list.Response.FirstOrDefault(t => t.Description == "Expansion Test Token");
if (testToken != null)
{
await _client.Token.Delete(testToken.AccessorID);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is unecessarily complicated. Maybe let's get rid of try/finally and just assume test always completes normally, so no exception handling is needed (which is generally true). There is no need to complicate the test code to handle edge cases.

Once the try/finally is removed , then we don't need to look for a token to delete since we already have its AccessorID.

Copy link
Copy Markdown
Contributor

@marcin-krystianc marcin-krystianc left a comment

Choose a reason for hiding this comment

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

I think this is a last remark, looks good otherwise!

Comment thread Consul/Token.cs Outdated
Comment on lines +52 to +55
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string[] NamespaceDefaultPolicyIDs { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string[] NamespaceDefaultRoleIDs { get; set; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would rather not add properties for which we do not have proper testing, it is better not to add them blindly (I'm not even sure when and how these would be non null):

Suggested change
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string[] NamespaceDefaultPolicyIDs { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string[] NamespaceDefaultRoleIDs { get; set; }

@marcin-krystianc marcin-krystianc changed the title [FEATURE] update ACL Token Read endpoint to add expnded parameter [FEATURE] update ACL Token Read endpoint to add expanded parameter Mar 24, 2026
@marcin-krystianc marcin-krystianc merged commit 345a236 into G-Research:master Mar 24, 2026
120 checks passed
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.

2 participants