Skip to content

feat: allow --tag in infisical secrets set #247

Open
mathnogueira wants to merge 3 commits into
mainfrom
matheus/create-secret-tag
Open

feat: allow --tag in infisical secrets set #247
mathnogueira wants to merge 3 commits into
mainfrom
matheus/create-secret-tag

Conversation

@mathnogueira
Copy link
Copy Markdown
Contributor

Description 📣

This allows the CLI to create/update a secret via infisical secrets set and set its tags with --tag.

It allows multiple --tag to be set. Following the same pattern of other tools, if the secret already exists and has tags, providing --tag will override the existing tags. If no --tag is provided, the existing tags will be preserved.

Type ✨

  • Bug fix
  • New feature
  • Improvement
  • Breaking change
  • Documentation

Tests 🛠️

  • Create a new secret with one tag
  • Create a new secret with multiple tags
  • Create multiple secrets with multiple tags
  • Updating a secret that has no tags
  • Updating a secret that has existing tags and see that they got overwritten
  • Don't pass --tag to an existing secret with tags and see that its tags got preserved
# Here's some code block to paste some code snippets

@infisical-review-police
Copy link
Copy Markdown

💬 Discussion in Slack: #pr-review-cli-247-allow-tag-in-infisical-secrets-set

Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel.

@mathnogueira mathnogueira changed the title allow --tag in infisical secrets set feat: allow --tag in infisical secrets set May 28, 2026
@mathnogueira mathnogueira requested a review from adilsitos May 28, 2026 21:49
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Greptile Summary

This PR adds --tag support to infisical secrets set, allowing users to attach one or more tags (by slug) when creating or updating secrets. Tags are resolved via a new GetTagBySlug API call, with auto-creation fallback via CreateTag; the UpdateRawSecretByNameV3Request and CreateRawSecretV3Request structs gain a TagIDs field sent in the existing create/PATCH endpoints.

  • Tag resolution: GetOrCreateTag resolves a slug to an ID, creating the tag if not found. All resolved IDs are compared against the secret's existing tag IDs to determine whether a PATCH is needed.
  • Preservation behavior: When no --tag flags are supplied, tagIds is omitted from the PATCH body (via omitempty), leaving existing tags untouched on the server side.
  • models.Tag.ID JSON key: The Tag.ID field changed from json:\"_id\" to json:\"id\" to align with the tag-specific API endpoints, but this assumption needs to hold for the tags embedded in secret list responses as well.

Confidence Score: 3/5

The feature logic is mostly sound, but the Tag.ID JSON key change in models.Tag touches a shared struct used to deserialize tags from the secrets list endpoint — if that endpoint returns _id (as every other entity in the codebase does), the comparison silently misfires on every set call for an already-tagged secret.

The new GetOrCreateTag helper and the tag-comparison block in SetRawSecrets work correctly when the API contract matches the changed JSON key, but that assumption is unverified. The rest of the codebase uniformly uses json:"_id" for embedded IDs, making the _idid change in models.Tag the highest-risk line in the diff. If incorrect, every infisical secrets set call on a secret with existing tags would silently trigger a spurious update.

packages/models/cli.go (the Tag.ID JSON key change) and packages/util/secrets.go (GetOrCreateTag auto-creation behavior) deserve a second look before merging.

Important Files Changed

Filename Overview
packages/models/cli.go Changed Tag.ID JSON tag from _id to id; risks breaking tag-ID parsing from secret list responses if the API still returns _id for embedded tags
packages/util/secrets.go Adds tag resolution and comparison logic to SetRawSecrets; GetOrCreateTag silently creates project tags on unknown slugs and doesn't deduplicate repeated slug inputs
packages/api/api.go Adds GetTagBySlug and CreateTag API helpers; both use url.PathEscape for path parameters and follow the existing error-handling pattern correctly
packages/api/model.go Adds TagIDs []string to RawSecret, CreateRawSecretV3Request, and UpdateRawSecretByNameV3Request; new SecretTag, GetTagBySlugResponse, CreateTagRequest, CreateTagResponse types look correct
packages/cmd/secrets.go Adds --tag StringArray flag and threads tags slice through to SetRawSecrets; wiring and flag registration look correct

Comments Outside Diff (1)

  1. packages/models/cli.go, line 34-39 (link)

    P1 Tag.ID JSON field key change may break tag comparison

    The ID field was renamed from json:"_id" to json:"id". This struct is consumed by GetRawSecretsV3Response.Secrets[i].Tags (see api/model.go:688) to parse tags that are embedded in the secrets list endpoint. Every other entity in this file and in api/model.go still uses json:"_id" (e.g., SingleEnvironmentVariable.ID, Workspace.ID). If the secrets list endpoint still returns _id for embedded tag objects, every tag.ID in the new comparison block (existingTagIds map) will be an empty string, causing the tags-changed check to always fire — silently triggering an update on every set call for an already-tagged secret.

Reviews (1): Last reviewed commit: "fix tag changed condition" | Re-trigger Greptile

Comment thread packages/util/secrets.go
Comment on lines 831 to +855
}

func GetOrCreateTag(client *resty.Client, projectId string, slug string) (api.SecretTag, error) {
tag, err := api.GetTagBySlug(client, projectId, slug)
if err == nil {
return tag, nil
}

var apiErr *api.APIError
if errors.As(err, &apiErr) {
if apiErr.StatusCode == http.StatusNotFound {
newTag, createErr := api.CreateTag(client, projectId, api.CreateTagRequest{
Slug: slug,
Color: "",
})
if createErr != nil {
return api.SecretTag{}, fmt.Errorf("could not create tag %q: [err=%v]", slug, createErr)
}

return newTag, nil
}
}

return api.SecretTag{}, fmt.Errorf("unable to resolve tag slug %q [err=%v]", slug, err)
}
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.

P2 Silent tag auto-creation on slug mismatch

GetOrCreateTag silently creates a new project tag whenever the given slug is not found. A single character typo (e.g. --tag producton) will permanently add a new tag to the project with an empty color string, with no warning to the user. Consider logging an informational message when a tag is created, or returning an error and asking the user to use infisical tags create explicitly.

Comment thread packages/util/secrets.go
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.

1 participant