Skip to content

Added label and attribute feature#9

Merged
MiaKoring merged 6 commits into
amethystsoft:mainfrom
MiaKoring:main
May 13, 2026
Merged

Added label and attribute feature#9
MiaKoring merged 6 commits into
amethystsoft:mainfrom
MiaKoring:main

Conversation

@MiaKoring
Copy link
Copy Markdown
Member

@MiaKoring MiaKoring commented May 13, 2026

Overview

This PR adds label and attribute metadata support to the Keyring API, enabling users to set a per-Keyring label on stored secrets and to retrieve key metadata (label, creation date, modification date).

Changes

Core Architecture

  • Keyring is refactored from public final class Keyring: Sendable to public struct Keyring: @unchecked Sendable, adding a stored label: String? and a fluent label(_:) -> Self configurator. Value semantics with a builder-style setter are a clean, low-friction design.

New Public APIs

  • New type: public struct Attributes: Sendable with:
    • public let label: String
    • public let created: Date
    • public let modified: Date
  • Sync subscript: public subscript(attributes key: String) -> Attributes? (noasync shim).
  • Async subscript: public subscript(asyncAttributes key: String) -> Attributes? { get async throws(SecSError) }.
  • Sync method: public func getAttributes(for key: String) throws(SecSError) -> Attributes? (noasync shim).
  • Async method: public func getAttributes(_ key: String, service: SecretService? = nil) async throws(SecSError) -> Attributes?.

Implementation details: the async API optionally accepts a SecretService and otherwise creates/uses a default connection; it ensures the service is connected, obtains (or creates) the default collection, finds the item for the key, reads DBus properties (Label, Created, Modified), converts timestamps to Date, and returns an Attributes instance (or nil when not found or on missing properties). The synchronous APIs route to the async-backed implementations via bridging and log errors before returning nil from the convenience subscript.

Persistence Behavior

  • Keyring._set(_:for:service:) now persists the configured label to the DBus item label property (replacing a prior TODO). Minor prompt-completion logic adjusted to ignore an unused local binding.

Tests

  • Updated integration tests to use a mutable keyring (letvar).
  • New tests:
    • testLabel verifies that applying .label(...) to a Keyring instance results in persisted attributes whose label matches the configured value (including after writing with a re-labeled Keyring).
    • testAttributes verifies attribute persistence and correctness: label, created/modified timestamps (asserting sensible changes within short windows), and cleanup of stored secrets at test end.

Documentation

  • Added DocC pages, examples, and tutorial quick-start demonstrating usage, batch operations, and attribute retrieval. Multiple example snippets show how to read attributes via subscript and getAttributes.

Strengths / Notable Good Work

  • The switch to a struct with an immutable fluent label(_:) setter is a thoughtful design delivering safer value semantics while preserving ergonomics.
  • The async attribute retrieval is robust: it gracefully handles optional external service injection, creates/uses the default collection, and carefully converts DBus timestamps to Date.
  • Tests exercise real integration flows (including timing assertions) which increases confidence in the feature.

Potential Review Notes

  • Concurrency: moving to @unchecked Sendable is reasonable here, but reviewers should confirm there's no hidden shared-mutable state that requires verified Sendable conformance.
  • Error handling: the synchronous convenience subscript logs and swallows errors returning nil — consider whether callers need visibility into specific failure modes.
  • Timestamp parsing: confirm time-zone and precision assumptions match expected semantics across environments.

Review Change Stack

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Warning

Rate limit exceeded

@MiaKoring has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 39 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f6d09ec0-be67-4e03-b1ec-8b48690c5f86

📥 Commits

Reviewing files that changed from the base of the PR and between 5c2a115 and 74f2058.

📒 Files selected for processing (4)
  • Sources/KeyringAccess/Documentation.docc/Documentation.md
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Attributes
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Delete
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Read
📝 Walkthrough

Walkthrough

This PR refactors Keyring to a struct with a label property, adds a Sendable Attributes type plus sync/async APIs to read item metadata from SecretService, persists label into item creation, adds integration tests for labeling/attributes, and expands DocC examples and tutorials.

Changes

Keyring Attributes and Label Feature

Layer / File(s) Summary
Keyring struct refactoring and label property
Sources/KeyringAccess/Keyring.swift
Keyring moved from public final class to public struct marked @unchecked Sendable, adds optional label stored property and a fluent label(_:) -> Self method.
Attributes type and metadata read APIs
Sources/KeyringAccess/Keyring+Attributes.swift
Adds public struct Attributes: Sendable (label, created, modified), sync/async subscripts ([attributes:], [asyncAttributes:]), sync getAttributes(for:) bridging to async via bridgeBlocking, and async getAttributes(_:service:) that connects to SecretService, finds the item, reads Label/Created/Modified, converts timestamps to Date, and returns Attributes?.
Label integration in item creation
Sources/KeyringAccess/Keyring+Set.swift
_set(_:for:service:) now writes the DBus "org.freedesktop.Secret.Item.Label" property using self.label ?? ""; post-prompt result objectPath is explicitly ignored.
Tests for label and attributes
Tests/KeyringAccessTests/KeyringAccessTests.swift
Updated existing tests to use mutable keyring. Added testLabel (verifies persisted label across writes) and testAttributes (validates label, created, modified timestamps and cleans up).
Documentation overview
Sources/KeyringAccess/Documentation.docc/Documentation.md
New overview page describing KeyringAccess purpose, features, and collection management behavior.
DocC batch examples
Sources/KeyringAccess/Documentation.docc/Resources/Batch/*
Added batch usage snippets demonstrating Keyring.runBatched and batched set usage.
Code example snippets
Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/*
Added and expanded code examples showing initialization, CRUD flows, attributes retrieval, updates, and deletion used by the tutorial.
Documentation package manifests
Sources/KeyringAccess/Documentation.docc/Resources/Package/*
Added example Swift Package manifests referenced by the docs.
DocC TOC and Quick Start tutorial
Sources/KeyringAccess/Documentation.docc/Table of Contents.tutorial, Sources/KeyringAccess/Documentation.docc/Tutorials/Quick start.tutorial
Added a Table of Contents and a Quick Start tutorial with Setup, Usage, and Batch sections linking to the new snippets.

Sequence Diagram

sequenceDiagram
  participant Keyring
  participant SecretService
  participant Collection
  participant Item
  Keyring->>SecretService: ensureConnected() / use provided or default service
  SecretService->>Collection: defaultCollection() / createIfMissing()
  Collection->>Item: searchForItem(label: key)
  Item->>Item: read properties ("Label","Created","Modified")
  Item->>Keyring: return Attributes(label, created, modified)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • amethystsoft/KeyringAccess#8: Provides foundational KeyringAccess API plumbing and SecretService integration helpers used by the new attributes and item-search logic.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding label configuration and attribute metadata retrieval features to the Keyring API.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

Copy link
Copy Markdown

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Tests/KeyringAccessTests/KeyringAccessTests.swift`:
- Around line 217-220: The early return after checking
newKeyring[asyncAttributes: key] skips the test cleanup and leaves state behind;
wrap the cleanup call in a defer placed immediately after opening/creating
newKeyring (or replace the early return with recording the issue and allowing
execution to reach the existing deletion code) so that the deletion always runs.
Specifically, adjust the code around newKeyring and the asyncAttributes: key
check so Issue.record("No attributes for the given key") is still executed but
control does not bypass the existing cleanup (use defer or ensure the
delete/cleanup call executes in all paths).
- Around line 223-231: The assertions compare timestamp differences but allow
large negative deltas; update the checks for newAttributes.created vs
creationTime and newAttributes.modified vs editTime to assert absolute deltas
(or assert 0 <= delta && delta <= 1.5) so that timestamps that are older than
expected fail—i.e., compute the delta for
newAttributes.created.timeIntervalSince1970 - creationTime.timeIntervalSince1970
and for newAttributes.modified.timeIntervalSince1970 -
editTime.timeIntervalSince1970 and verify the absolute value is <= 1.5 (or the
delta is between 0 and 1.5).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ec4712e-ba3a-494f-9f15-8c1845d2abed

📥 Commits

Reviewing files that changed from the base of the PR and between 351c887 and 77c2e8b.

📒 Files selected for processing (4)
  • Sources/KeyringAccess/Keyring+Attributes.swift
  • Sources/KeyringAccess/Keyring+Set.swift
  • Sources/KeyringAccess/Keyring.swift
  • Tests/KeyringAccessTests/KeyringAccessTests.swift

Comment thread Tests/KeyringAccessTests/KeyringAccessTests.swift
Comment thread Tests/KeyringAccessTests/KeyringAccessTests.swift
Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/KeyringAccess/Documentation.docc/Documentation.md`:
- Line 16: The phrase "usecase" in the "Subscript and get/set Support" sentence
is misspelled; update that sentence to use "use case" (two words) instead of
"usecase" so the line reads "...depending on what fits your use case better." to
fix the spelling in Documentation.md.

In
`@Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Read`:
- Around line 23-26: The example declares two variables named `secret` (from
keyring["user"] and keyring.get(for: "user")) causing a redeclaration error; fix
it by renaming one of them (e.g., rename the result of `keyring.get(for:
"user")` to `secretViaGetter`) or by removing the second `let` and assigning
into the existing `secret` (e.g., `secret = keyring.get(for: "user")`), updating
references accordingly so both `keyring["user"]` and `keyring.get(for: "user")`
are shown without duplicate variable declarations.

In
`@Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-AddedDependency`:
- Around line 14-16: The YourApp executable target is missing a dependency on
the KeyringAccess product, so it cannot import KeyringAccess; update the YourApp
.executableTarget declaration to include a package product dependency on the
KeyringAccess product (i.e., add a .product dependency referencing product name
"KeyringAccess" and the package name used in Package.swift) so the target can
import and use KeyringAccess.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eb11b9aa-9d35-4e4c-9bae-e4f82c7538c2

📥 Commits

Reviewing files that changed from the base of the PR and between 77c2e8b and 5c2a115.

📒 Files selected for processing (17)
  • Sources/KeyringAccess/Documentation.docc/Documentation.md
  • Sources/KeyringAccess/Documentation.docc/Resources/Batch/BatchBase
  • Sources/KeyringAccess/Documentation.docc/Resources/Batch/BatchOperation
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Attributes
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Delete
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Keyring
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Read
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Store
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Update
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-init
  • Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-AddedDependency
  • Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-AddedDependencyApp
  • Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-Base
  • Sources/KeyringAccess/Documentation.docc/Table of Contents.tutorial
  • Sources/KeyringAccess/Documentation.docc/Tutorials/Quick start.tutorial
  • Tests/KeyringAccessTests/KeyringAccessTests.swift
✅ Files skipped from review due to trivial changes (12)
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Delete
  • Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-AddedDependencyApp
  • Sources/KeyringAccess/Documentation.docc/Resources/Package/IntroductionPackage-Base
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-init
  • Sources/KeyringAccess/Documentation.docc/Tutorials/Quick start.tutorial
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Attributes
  • Sources/KeyringAccess/Documentation.docc/Resources/Batch/BatchBase
  • Sources/KeyringAccess/Documentation.docc/Table of Contents.tutorial
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Keyring
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base
  • Sources/KeyringAccess/Documentation.docc/Resources/Batch/BatchOperation
  • Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Store
🚧 Files skipped from review as they are similar to previous changes (1)
  • Tests/KeyringAccessTests/KeyringAccessTests.swift

Comment thread Sources/KeyringAccess/Documentation.docc/Documentation.md Outdated
Comment thread Sources/KeyringAccess/Documentation.docc/Resources/CodeExample/Code-Base-Read Outdated
@MiaKoring MiaKoring merged commit 3210abe into amethystsoft:main May 13, 2026
2 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.

1 participant