familia 2.11.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ci.yml +1 -1
- data/.github/workflows/claude-code-review.yml +33 -9
- data/.github/workflows/claude.yml +9 -2
- data/.github/workflows/code-smells.yml +2 -2
- data/.github/workflows/codeql.yml +101 -0
- data/.github/workflows/release-gem.yml +5 -5
- data/.github/workflows/ruby-lint.yml +66 -0
- data/.github/workflows/yardoc.yml +110 -0
- data/.yardopts +1 -1
- data/CHANGELOG.rst +116 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +12 -20
- data/Rakefile +10 -0
- data/docs/guides/feature-encrypted-fields.md +41 -11
- data/docs/investigation/memory-audit.md +465 -0
- data/docs/overview.md +1 -1
- data/examples/encryption_upgrade_proof/.gitignore +3 -0
- data/examples/encryption_upgrade_proof/README.md +84 -0
- data/examples/encryption_upgrade_proof/common.rb +83 -0
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.dev-no-libsodium +4 -0
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.dev-with-libsodium +5 -0
- data/examples/encryption_upgrade_proof/gemfiles/Gemfile.production-today +4 -0
- data/examples/encryption_upgrade_proof/model.rb +32 -0
- data/examples/encryption_upgrade_proof/phase0_production_today.rb +100 -0
- data/examples/encryption_upgrade_proof/phase1_gem_upgrade_no_libsodium.rb +99 -0
- data/examples/encryption_upgrade_proof/phase2_libsodium_enabled.rb +297 -0
- data/examples/encryption_upgrade_proof/phase3_rollback_hazard.rb +56 -0
- data/examples/encryption_upgrade_proof/run.sh +60 -0
- data/lib/familia/data_type/database_commands.rb +8 -1
- data/lib/familia/data_type/types/stringkey.rb +10 -3
- data/lib/familia/encryption/provider.rb +9 -0
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +4 -0
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +4 -0
- data/lib/familia/encryption/registry.rb +47 -5
- data/lib/familia/encryption.rb +19 -37
- data/lib/familia/features/encrypted_fields/concealed_string.rb +27 -0
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +21 -3
- data/lib/familia/features/encrypted_fields.rb +27 -4
- data/lib/familia/verifiable_identifier.rb +24 -11
- data/lib/familia/version.rb +1 -1
- data/try/bug_fixes/stringkey_exists_try.rb +153 -0
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +15 -24
- data/try/features/encrypted_fields/per_field_algorithm_try.rb +164 -0
- data/try/features/encryption/algorithm_upgrade_try.rb +116 -0
- data/try/features/encryption/registry_algorithm_resolution_try.rb +125 -0
- data/try/integration/verifiable_identifier_try.rb +66 -2
- data/try/investigation/memory_leak_proof.rb +415 -0
- data/try/investigation/process_memory_leak_proof.rb +205 -0
- data/try/unit/data_types/enumerable_consistency/large_scale_consistency_try.rb +34 -8
- metadata +24 -2
- data/.github/workflows/docs.yml +0 -87
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 515d7050ae261290c4e85c6757a68edaa2aae60e21e05b9a6d1fd0457d90fad5
|
|
4
|
+
data.tar.gz: 653efc3da9a21910e7e071ae3065ab06e730334226d8f4820c0ed692fbec8453
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9e82443e034e2a2457bdc5366edcc18586d5df1f1ef4e60dc8c50d3d7431850c8899c42e15200d8ad0638455f13f2024a357b5e904f424fc9315312194329cce
|
|
7
|
+
data.tar.gz: 5eed6b2a2017510bac669b43602a1960b0719fa839eb8e61114be27df7010ea4d90eb73abdefc202b86e6c05d0e9dc674087e90e8c828dd649aaad4c446d38a4
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "github-actions"
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
12
|
+
- package-ecosystem: "bundler"
|
|
13
|
+
directory: "/" # Location of package manifests
|
|
14
|
+
schedule:
|
|
15
|
+
interval: "weekly"
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -4,14 +4,34 @@ on:
|
|
|
4
4
|
pull_request:
|
|
5
5
|
types: [opened, synchronize, labeled]
|
|
6
6
|
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
model:
|
|
9
|
+
description: "Claude model for this run (overrides the CLAUDE_MODEL repo variable)"
|
|
10
|
+
type: choice
|
|
11
|
+
required: false
|
|
12
|
+
default: claude-opus-4-6
|
|
13
|
+
options:
|
|
14
|
+
- claude-opus-4-6
|
|
15
|
+
- claude-sonnet-4-6
|
|
16
|
+
- claude-haiku-4-5-20251001
|
|
7
17
|
|
|
8
18
|
jobs:
|
|
9
19
|
claude-review:
|
|
10
|
-
# Run
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
# Run only when ALL of the following hold:
|
|
21
|
+
# 1. Author is not a bot (renovate, dependabot, etc. surface as 'name[bot]').
|
|
22
|
+
# 2. PR head is not from a fork. Fork PRs run without repository secrets, so
|
|
23
|
+
# CLAUDE_CODE_OAUTH_TOKEN is empty and the action would fail.
|
|
24
|
+
# 3. The event is a freshly opened PR, a 'claude-review' label add, or a push
|
|
25
|
+
# to a PR that already carries the 'claude-review' label.
|
|
26
|
+
if: ${{
|
|
27
|
+
!endsWith(github.actor, '[bot]') &&
|
|
28
|
+
!github.event.pull_request.head.repo.fork &&
|
|
29
|
+
(
|
|
30
|
+
(github.event.action == 'opened') ||
|
|
31
|
+
(github.event.action == 'labeled' && github.event.label.name == 'claude-review') ||
|
|
32
|
+
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'claude-review'))
|
|
33
|
+
)
|
|
34
|
+
}}
|
|
15
35
|
|
|
16
36
|
runs-on: ubuntu-latest
|
|
17
37
|
permissions:
|
|
@@ -22,7 +42,7 @@ jobs:
|
|
|
22
42
|
|
|
23
43
|
steps:
|
|
24
44
|
- name: Checkout repository
|
|
25
|
-
uses: actions/checkout@
|
|
45
|
+
uses: actions/checkout@v7
|
|
26
46
|
with:
|
|
27
47
|
fetch-depth: 1
|
|
28
48
|
|
|
@@ -32,6 +52,13 @@ jobs:
|
|
|
32
52
|
with:
|
|
33
53
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
34
54
|
|
|
55
|
+
# Primary model precedence: the workflow_dispatch "model" input (manual
|
|
56
|
+
# runs) -> the CLAUDE_MODEL repo variable -> this built-in default.
|
|
57
|
+
# Pinning a current id avoids the action's frozen default, which 404s
|
|
58
|
+
# ("model: claude-sonnet-4-20250514"). Fall back to Sonnet on overload.
|
|
59
|
+
model: "${{ inputs.model || vars.CLAUDE_MODEL || 'claude-opus-4-6' }}"
|
|
60
|
+
fallback_model: "${{ vars.CLAUDE_FALLBACK_MODEL || 'claude-sonnet-4-6' }}"
|
|
61
|
+
|
|
35
62
|
# Optional: Use sticky comments to make Claude reuse the same comment on subsequent pushes to the same PR
|
|
36
63
|
use_sticky_comment: true
|
|
37
64
|
|
|
@@ -50,6 +77,3 @@ jobs:
|
|
|
50
77
|
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
51
78
|
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
|
52
79
|
allowed_tools: "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"
|
|
53
|
-
|
|
54
|
-
# Allow bot-initiated workflows (e.g., qodo, dependabot)
|
|
55
|
-
allowed_bots: "*"
|
|
@@ -26,16 +26,23 @@ jobs:
|
|
|
26
26
|
actions: read # Required for Claude to read CI results on PRs
|
|
27
27
|
steps:
|
|
28
28
|
- name: Checkout repository
|
|
29
|
-
uses: actions/checkout@
|
|
29
|
+
uses: actions/checkout@v7
|
|
30
30
|
with:
|
|
31
31
|
fetch-depth: 1
|
|
32
32
|
|
|
33
33
|
- name: Run Claude Code
|
|
34
34
|
id: claude
|
|
35
|
-
uses: anthropics/claude-code-action@
|
|
35
|
+
uses: anthropics/claude-code-action@beta
|
|
36
36
|
with:
|
|
37
37
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
38
|
|
|
39
|
+
# Primary model: set the CLAUDE_MODEL repo variable to override without
|
|
40
|
+
# editing this file. Pinning a current id avoids the action's frozen
|
|
41
|
+
# default, which 404s ("model: claude-sonnet-4-20250514"). Fall back to
|
|
42
|
+
# Sonnet if the primary is unavailable or overloaded.
|
|
43
|
+
model: "${{ vars.CLAUDE_MODEL || 'claude-opus-4-6' }}"
|
|
44
|
+
fallback_model: "${{ vars.CLAUDE_FALLBACK_MODEL || 'claude-sonnet-4-6' }}"
|
|
45
|
+
|
|
39
46
|
# This is an optional setting that allows Claude to read CI results on PRs
|
|
40
47
|
additional_permissions: |
|
|
41
48
|
actions: read
|
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- name: Checkout code
|
|
24
|
-
uses: actions/checkout@
|
|
24
|
+
uses: actions/checkout@v7
|
|
25
25
|
|
|
26
26
|
- name: Set up Ruby
|
|
27
27
|
uses: ruby/setup-ruby@v1
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
|
|
92
92
|
steps:
|
|
93
93
|
- name: Checkout code
|
|
94
|
-
uses: actions/checkout@
|
|
94
|
+
uses: actions/checkout@v7
|
|
95
95
|
|
|
96
96
|
- name: Set up Ruby
|
|
97
97
|
uses: ruby/setup-ruby@v1
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL Advanced"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ "main" ]
|
|
17
|
+
pull_request:
|
|
18
|
+
branches: [ "main" ]
|
|
19
|
+
schedule:
|
|
20
|
+
- cron: '30 0 * * 6'
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
analyze:
|
|
24
|
+
name: Analyze (${{ matrix.language }})
|
|
25
|
+
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
|
26
|
+
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
|
27
|
+
# - https://gh.io/supported-runners-and-hardware-resources
|
|
28
|
+
# - https://gh.io/using-larger-runners (GitHub.com only)
|
|
29
|
+
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
|
30
|
+
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
31
|
+
permissions:
|
|
32
|
+
# required for all workflows
|
|
33
|
+
security-events: write
|
|
34
|
+
|
|
35
|
+
# required to fetch internal or private CodeQL packs
|
|
36
|
+
packages: read
|
|
37
|
+
|
|
38
|
+
# only required for workflows in private repositories
|
|
39
|
+
actions: read
|
|
40
|
+
contents: read
|
|
41
|
+
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
include:
|
|
46
|
+
- language: actions
|
|
47
|
+
build-mode: none
|
|
48
|
+
- language: ruby
|
|
49
|
+
build-mode: none
|
|
50
|
+
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
|
|
51
|
+
# Use `c-cpp` to analyze code written in C, C++ or both
|
|
52
|
+
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
|
53
|
+
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
|
54
|
+
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
|
55
|
+
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
|
56
|
+
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
|
57
|
+
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
|
58
|
+
steps:
|
|
59
|
+
- name: Checkout repository
|
|
60
|
+
uses: actions/checkout@v7
|
|
61
|
+
|
|
62
|
+
# Add any setup steps before running the `github/codeql-action/init` action.
|
|
63
|
+
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
|
64
|
+
# or others). This is typically only required for manual builds.
|
|
65
|
+
# - name: Setup runtime (example)
|
|
66
|
+
# uses: actions/setup-example@v1
|
|
67
|
+
|
|
68
|
+
# Initializes the CodeQL tools for scanning.
|
|
69
|
+
- name: Initialize CodeQL
|
|
70
|
+
uses: github/codeql-action/init@v4
|
|
71
|
+
with:
|
|
72
|
+
languages: ${{ matrix.language }}
|
|
73
|
+
build-mode: ${{ matrix.build-mode }}
|
|
74
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
75
|
+
# By default, queries listed here will override any specified in a config file.
|
|
76
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
77
|
+
|
|
78
|
+
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
79
|
+
# queries: security-extended,security-and-quality
|
|
80
|
+
|
|
81
|
+
# If the analyze step fails for one of the languages you are analyzing with
|
|
82
|
+
# "We were unable to automatically build your code", modify the matrix above
|
|
83
|
+
# to set the build mode to "manual" for that language. Then modify this step
|
|
84
|
+
# to build your code.
|
|
85
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
86
|
+
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
87
|
+
- name: Run manual build steps
|
|
88
|
+
if: matrix.build-mode == 'manual'
|
|
89
|
+
shell: bash
|
|
90
|
+
run: |
|
|
91
|
+
echo 'If you are using a "manual" build mode for one or more of the' \
|
|
92
|
+
'languages you are analyzing, replace this with the commands to build' \
|
|
93
|
+
'your code, for example:'
|
|
94
|
+
echo ' make bootstrap'
|
|
95
|
+
echo ' make release'
|
|
96
|
+
exit 1
|
|
97
|
+
|
|
98
|
+
- name: Perform CodeQL Analysis
|
|
99
|
+
uses: github/codeql-action/analyze@v4
|
|
100
|
+
with:
|
|
101
|
+
category: "/language:${{matrix.language}}"
|
|
@@ -124,7 +124,7 @@ jobs:
|
|
|
124
124
|
|
|
125
125
|
steps:
|
|
126
126
|
- name: Checkout
|
|
127
|
-
uses: actions/checkout@
|
|
127
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
128
128
|
with:
|
|
129
129
|
persist-credentials: false
|
|
130
130
|
|
|
@@ -132,10 +132,10 @@ jobs:
|
|
|
132
132
|
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
|
|
133
133
|
with:
|
|
134
134
|
bundler-cache: true
|
|
135
|
-
# Pinned to 3.
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
ruby-version: "3.
|
|
135
|
+
# Pinned to 3.3 to match the otto/rhales release builds. The gem is
|
|
136
|
+
# pure Ruby, so the build Ruby is independent of the supported range
|
|
137
|
+
# declared in the gemspec (>= 3.2).
|
|
138
|
+
ruby-version: "3.3"
|
|
139
139
|
|
|
140
140
|
- name: Verify release tag matches Familia::VERSION
|
|
141
141
|
env:
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# .github/workflows/ruby-lint.yml
|
|
2
|
+
|
|
3
|
+
name: Ruby Lint
|
|
4
|
+
|
|
5
|
+
# Runs RuboCop across the supported Ruby versions. Linting is informational:
|
|
6
|
+
# every dependency/lint step is continue-on-error, so style findings surface as
|
|
7
|
+
# annotations without blocking merges.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches:
|
|
12
|
+
- fix/*
|
|
13
|
+
- rel/*
|
|
14
|
+
pull_request:
|
|
15
|
+
branches:
|
|
16
|
+
- main
|
|
17
|
+
- develop
|
|
18
|
+
- feature/*
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
inputs:
|
|
21
|
+
debug_enabled:
|
|
22
|
+
type: boolean
|
|
23
|
+
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
|
24
|
+
required: false
|
|
25
|
+
default: false
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: read
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
lint:
|
|
32
|
+
timeout-minutes: 10 # prevent hung jobs
|
|
33
|
+
|
|
34
|
+
runs-on: ubuntu-24.04
|
|
35
|
+
|
|
36
|
+
strategy:
|
|
37
|
+
fail-fast: true
|
|
38
|
+
matrix:
|
|
39
|
+
ruby: ['3.2', '3.3', '3.4', '3.5', '4.0']
|
|
40
|
+
continue-on-error: [true]
|
|
41
|
+
|
|
42
|
+
steps:
|
|
43
|
+
- name: Checkout code
|
|
44
|
+
uses: actions/checkout@v7
|
|
45
|
+
|
|
46
|
+
- uses: ruby/setup-ruby@v1
|
|
47
|
+
with:
|
|
48
|
+
ruby-version: ${{ matrix.ruby }}
|
|
49
|
+
bundler-cache: true
|
|
50
|
+
|
|
51
|
+
- name: Setup tmate session
|
|
52
|
+
uses: mxschmitt/action-tmate@7b6a61a73bbb9793cb80ad69b8dd8ac19261834c # v3
|
|
53
|
+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
|
|
54
|
+
with:
|
|
55
|
+
detached: true
|
|
56
|
+
|
|
57
|
+
- name: Install dependencies
|
|
58
|
+
continue-on-error: ${{ matrix.continue-on-error }}
|
|
59
|
+
run: |
|
|
60
|
+
bundle config path vendor/bundle
|
|
61
|
+
bundle install --jobs 4 --retry 3
|
|
62
|
+
|
|
63
|
+
- name: Run Rubocop
|
|
64
|
+
continue-on-error: ${{ matrix.continue-on-error }}
|
|
65
|
+
run: |
|
|
66
|
+
bundle exec rubocop --config .rubocop.yml --format json --fail-level warning
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
name: Generate and Deploy YARD Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- 'lib/**/*'
|
|
9
|
+
- 'docs/**/*'
|
|
10
|
+
- 'README.md'
|
|
11
|
+
- 'CHANGELOG.md'
|
|
12
|
+
- 'CHANGELOG.rst'
|
|
13
|
+
- 'LICENSE.txt'
|
|
14
|
+
- '.yardopts'
|
|
15
|
+
- '.github/workflows/yardoc.yml'
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
pages: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
# Allow only one concurrent deployment, skipping runs queued between the run
|
|
24
|
+
# in-progress and latest queued. Do NOT cancel in-progress runs so production
|
|
25
|
+
# deployments can complete.
|
|
26
|
+
concurrency:
|
|
27
|
+
group: "pages"
|
|
28
|
+
cancel-in-progress: false
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
build-docs:
|
|
32
|
+
timeout-minutes: 10
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
name: Generate YARD Documentation
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: Checkout repository
|
|
38
|
+
uses: actions/checkout@v7
|
|
39
|
+
with:
|
|
40
|
+
fetch-depth: 0
|
|
41
|
+
|
|
42
|
+
- name: Set up Ruby environment
|
|
43
|
+
uses: ruby/setup-ruby@v1
|
|
44
|
+
with:
|
|
45
|
+
ruby-version: '3.4'
|
|
46
|
+
bundler-cache: true
|
|
47
|
+
|
|
48
|
+
- name: Generate documentation
|
|
49
|
+
# Uses the repository's committed .yardopts as the single source of
|
|
50
|
+
# truth for the output dir, includes/excludes, markup, and tags.
|
|
51
|
+
run: |
|
|
52
|
+
echo "::group::YARD Documentation Generation"
|
|
53
|
+
bundle exec yard stats --list-undoc || true
|
|
54
|
+
bundle exec yard doc
|
|
55
|
+
echo "::endgroup::"
|
|
56
|
+
|
|
57
|
+
- name: Disable Jekyll processing
|
|
58
|
+
# YARD emits files and directories that begin with underscores; the
|
|
59
|
+
# .nojekyll marker stops GitHub Pages from stripping them.
|
|
60
|
+
run: touch doc/.nojekyll
|
|
61
|
+
|
|
62
|
+
- name: Validate documentation output
|
|
63
|
+
run: |
|
|
64
|
+
echo "::group::Documentation Validation"
|
|
65
|
+
if [ ! -d "doc" ]; then
|
|
66
|
+
echo "Error: documentation directory 'doc' was not generated." >&2
|
|
67
|
+
echo "Ensure .yardopts sets '--output-dir doc'." >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
if [ ! -f "doc/index.html" ]; then
|
|
71
|
+
echo "Warning: doc/index.html not found"
|
|
72
|
+
fi
|
|
73
|
+
echo "Generated HTML files: $(find doc -name '*.html' | wc -l)"
|
|
74
|
+
echo "Total documentation size: $(du -sh doc/ | cut -f1)"
|
|
75
|
+
echo "::endgroup::"
|
|
76
|
+
|
|
77
|
+
- name: Setup GitHub Pages configuration
|
|
78
|
+
uses: actions/configure-pages@v4
|
|
79
|
+
|
|
80
|
+
- name: Upload documentation artifact
|
|
81
|
+
uses: actions/upload-pages-artifact@v5
|
|
82
|
+
with:
|
|
83
|
+
path: './doc'
|
|
84
|
+
|
|
85
|
+
deploy-pages:
|
|
86
|
+
timeout-minutes: 10
|
|
87
|
+
environment:
|
|
88
|
+
name: github-pages
|
|
89
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
90
|
+
runs-on: ubuntu-latest
|
|
91
|
+
needs: build-docs
|
|
92
|
+
outputs:
|
|
93
|
+
page_url: ${{ steps.deployment.outputs.page_url }}
|
|
94
|
+
|
|
95
|
+
steps:
|
|
96
|
+
- name: Deploy to GitHub Pages
|
|
97
|
+
id: deployment
|
|
98
|
+
uses: actions/deploy-pages@v5
|
|
99
|
+
|
|
100
|
+
notify-completion:
|
|
101
|
+
timeout-minutes: 5
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
needs: [build-docs, deploy-pages]
|
|
104
|
+
if: success()
|
|
105
|
+
|
|
106
|
+
steps:
|
|
107
|
+
- name: Documentation deployment summary
|
|
108
|
+
run: |
|
|
109
|
+
echo "::notice title=Documentation Deployed::YARD documentation successfully deployed to GitHub Pages"
|
|
110
|
+
echo "::notice title=Access URL::Documentation available at: ${{ needs.deploy-pages.outputs.page_url }}"
|
data/.yardopts
CHANGED
data/CHANGELOG.rst
CHANGED
|
@@ -7,6 +7,122 @@ The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`
|
|
|
7
7
|
|
|
8
8
|
<!--scriv-insert-here-->
|
|
9
9
|
|
|
10
|
+
.. _changelog-2.11.1:
|
|
11
|
+
|
|
12
|
+
2.11.1 — 2026-07-04
|
|
13
|
+
===================
|
|
14
|
+
|
|
15
|
+
Added
|
|
16
|
+
-----
|
|
17
|
+
|
|
18
|
+
- ``encrypted_field`` now honors a per-field ``algorithm:`` option, pinning that
|
|
19
|
+
field's write algorithm to a specific registered provider (``'aes-256-gcm'`` or
|
|
20
|
+
``'xchacha20poly1305'``) independent of the registry's default-provider
|
|
21
|
+
priority. The option was previously documented but silently ignored, so writes
|
|
22
|
+
always used the default provider. Decryption stays envelope-driven, so a pin can
|
|
23
|
+
be added, changed, or removed without breaking ciphertext already at rest, and
|
|
24
|
+
``re_encrypt_fields!`` re-encrypts under the pin rather than the default. This is
|
|
25
|
+
the supported lever for a reader-before-writer format migration: deploy
|
|
26
|
+
``rbnacl`` fleet-wide so every node can *read* XChaCha20-Poly1305 while keeping
|
|
27
|
+
*writes* pinned to AES-256-GCM until all readers are confirmed capable, then drop
|
|
28
|
+
the pin. Issue #334
|
|
29
|
+
|
|
30
|
+
Changed
|
|
31
|
+
-------
|
|
32
|
+
|
|
33
|
+
- ``Familia::Encryption::Registry.get`` now distinguishes an unknown algorithm
|
|
34
|
+
from a *known* algorithm whose provider is not available on the current node.
|
|
35
|
+
Because ``Registry.register`` only stores providers whose runtime dependency is
|
|
36
|
+
present, pinning ``encrypted_field ..., algorithm: 'xchacha20poly1305'`` on a
|
|
37
|
+
node without ``rbnacl``/libsodium previously raised the misleading
|
|
38
|
+
``"Unsupported algorithm: xchacha20poly1305"`` -- pointing an operator at a typo
|
|
39
|
+
when the real fix is a missing dependency. It now names the provider, explains
|
|
40
|
+
the dependency is missing, and (because ``get`` runs on both the encrypt and
|
|
41
|
+
decrypt paths) states that installing the dependency is what enables reading
|
|
42
|
+
*and* writing the algorithm, framing an algorithm pin as a write-time
|
|
43
|
+
workaround that cannot decrypt existing ciphertext. Each provider declares its
|
|
44
|
+
own dependency via a new ``Provider.dependency_hint`` class method (nil for
|
|
45
|
+
always-available providers like OpenSSL AES-256-GCM), so the generic error path
|
|
46
|
+
names the correct library as providers are added rather than hardcoding any one
|
|
47
|
+
of them. The set of registerable providers is centralized in
|
|
48
|
+
``Registry.known_providers``, the single source of truth shared by ``setup!``
|
|
49
|
+
and ``get``. Error-message and internal-refactor only; the resolution of every
|
|
50
|
+
available algorithm is unchanged. Issue #334
|
|
51
|
+
|
|
52
|
+
Fixed
|
|
53
|
+
-----
|
|
54
|
+
|
|
55
|
+
- ``Familia::DataType#exists?`` no longer returns ``true`` for a deleted or
|
|
56
|
+
never-created scalar key (``StringKey``, ``Counter``, ``Lock``,
|
|
57
|
+
``JsonStringKey``). The check was ``dbclient.exists(dbkey) && !size.zero?``,
|
|
58
|
+
but ``EXISTS`` returns an Integer count and ``0`` is truthy in Ruby, so the
|
|
59
|
+
guard never short-circuited on a missing key -- existence was decided
|
|
60
|
+
entirely by the size check. ``exists?`` now uses a boolean-coerced ``EXISTS``
|
|
61
|
+
count directly. Issue #331
|
|
62
|
+
|
|
63
|
+
- Relatedly, ``StringKey#size``/``#length``/``#empty?`` (and ``Lock``'s) no
|
|
64
|
+
longer reflect the never-nil ``#to_s`` fallback. ``#char_count`` derived from
|
|
65
|
+
``#to_s.size``, and ``#to_s`` intentionally returns ``Familia::Base``'s
|
|
66
|
+
documented "never nil" inspect-string when the value is absent -- so
|
|
67
|
+
``#size`` was non-zero (and ``#empty?`` false) for a missing key.
|
|
68
|
+
``#char_count`` now reads ``#value`` directly; ``#to_s`` is left unchanged.
|
|
69
|
+
Issue #331
|
|
70
|
+
|
|
71
|
+
- ``encrypted_fields_status`` now reports each field's real algorithm for a live
|
|
72
|
+
encrypted value (e.g. ``{ encrypted: true, algorithm: "aes-256-gcm", cleared:
|
|
73
|
+
false }``), honoring any per-field pin. Previously it returned ``{ encrypted:
|
|
74
|
+
false, value: "[CONCEALED]" }`` for every encrypted field, because
|
|
75
|
+
``ConcealedString`` had no ``concealed?`` predicate for the status check to
|
|
76
|
+
match -- so the algorithm shown in the method's docstring and the guides was
|
|
77
|
+
never actually produced. ``ConcealedString`` gains ``#concealed?`` and
|
|
78
|
+
``#algorithm`` readers (the latter reads the stored envelope). Issue #334
|
|
79
|
+
|
|
80
|
+
Documentation
|
|
81
|
+
-------------
|
|
82
|
+
|
|
83
|
+
- Added an executable, multi-phase proof (``examples/encryption_upgrade_proof/``)
|
|
84
|
+
demonstrating that installing ``rbnacl`` safely flips new writes to
|
|
85
|
+
XChaCha20-Poly1305 while every existing AES-256-GCM envelope — including
|
|
86
|
+
ciphertext written by the released 2.10.1 gem, under the pre-#310 static HKDF
|
|
87
|
+
salt, and under a retired master key version — keeps decrypting. Also pins,
|
|
88
|
+
as deliberately-passing checks, two operational hazards: the XChaCha
|
|
89
|
+
``encryption_personalization`` cannot be rotated (no history/fallback like
|
|
90
|
+
``encryption_hkdf_salt_history``), and once any XChaCha envelope exists,
|
|
91
|
+
every node that may read it needs libsodium installed. PR #330
|
|
92
|
+
|
|
93
|
+
- The encrypted-fields guide previously showed a ``provider: :aes_gcm`` field
|
|
94
|
+
option that was never implemented; those examples now use the real
|
|
95
|
+
``algorithm: 'aes-256-gcm'`` form, and the ``Familia::Encryption`` facade
|
|
96
|
+
docstring documents the shipped behavior instead of a hypothetical
|
|
97
|
+
implementation sketch. The ``encrypted_fields_status`` output examples across
|
|
98
|
+
the guides and the overview were corrected to match what the method now
|
|
99
|
+
returns. Issue #334
|
|
100
|
+
|
|
101
|
+
- Added a memory-audit investigation (``docs/investigation/memory-audit.md``)
|
|
102
|
+
diagnosing #309's ``<collection>_with_permission`` O(N) query as a transient,
|
|
103
|
+
GC-reclaimable spike rather than a per-process leak, and auditing the rest of
|
|
104
|
+
``lib/`` for per-process growth (concluding Familia has no unconditional leak).
|
|
105
|
+
Ships two executable proofs in ``try/investigation/`` — a pure-Ruby
|
|
106
|
+
``process_memory_leak_proof.rb`` and a live-Redis ``memory_leak_proof.rb``.
|
|
107
|
+
Diagnosis only; no runtime behaviour is changed by the investigation. Issue #309
|
|
108
|
+
|
|
109
|
+
AI Assistance
|
|
110
|
+
-------------
|
|
111
|
+
|
|
112
|
+
- The encryption upgrade proof, its regression tryouts, and this changelog
|
|
113
|
+
entry were drafted with AI assistance. PR #330
|
|
114
|
+
|
|
115
|
+
- The ``exists?`` fix and its regression tryouts were drafted with AI
|
|
116
|
+
assistance. Issue #331
|
|
117
|
+
|
|
118
|
+
- The per-field algorithm implementation, the ``encrypted_fields_status`` fix,
|
|
119
|
+
their regression tryouts, the guide corrections, and the
|
|
120
|
+
``Registry.get`` error-message refinement were drafted with AI assistance.
|
|
121
|
+
Issue #334
|
|
122
|
+
|
|
123
|
+
- The memory-audit investigation and its executable proofs were drafted with AI
|
|
124
|
+
assistance. Issue #309
|
|
125
|
+
|
|
10
126
|
.. _changelog-2.11.0:
|
|
11
127
|
|
|
12
128
|
2.11.0 — 2026-06-22
|
data/Gemfile
CHANGED
|
@@ -5,7 +5,7 @@ source 'https://rubygems.org'
|
|
|
5
5
|
gemspec
|
|
6
6
|
|
|
7
7
|
group :test do
|
|
8
|
-
gem 'concurrent-ruby', '~> 1.3.
|
|
8
|
+
gem 'concurrent-ruby', '~> 1.3.7', require: false
|
|
9
9
|
gem 'ruby-prof'
|
|
10
10
|
gem 'stackprof'
|
|
11
11
|
gem 'timecop', require: false
|
|
@@ -21,12 +21,12 @@ group :development, :test do
|
|
|
21
21
|
# Config#to_data, which we don't use (we don't use Dry::Configurable at all),
|
|
22
22
|
# so cap below 1.4 to keep the dev bundle installable on Ruby 3.2.
|
|
23
23
|
gem 'dry-configurable', '>= 1.3', '< 1.5', require: false
|
|
24
|
-
gem 'irb', '~> 1.
|
|
24
|
+
gem 'irb', '~> 1.18.0', require: false
|
|
25
25
|
gem 'json_schemer', '~> 2.0', require: false
|
|
26
26
|
gem 'rake', '~> 13.0', require: false
|
|
27
27
|
gem 'redcarpet', require: false
|
|
28
28
|
gem 'reek', require: false
|
|
29
|
-
gem 'rubocop', '~> 1.
|
|
29
|
+
gem 'rubocop', '~> 1.88.0', require: false
|
|
30
30
|
gem 'rubocop-performance', require: false
|
|
31
31
|
gem 'rubocop-thread_safety', require: false
|
|
32
32
|
gem 'ruby-lsp', require: false
|