activerecord-s3-bucket-name-validator 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 89b7cdcea9fd4f03a6d9435bf462f69d5fd2c9da5c75fb1c1742e54c520cc444
4
+ data.tar.gz: 1f3cc7c5692a601ef628e0e4bd3ce59c318d323fac52cc5c44fffc448cb6f503
5
+ SHA512:
6
+ metadata.gz: 70654a96c3d0ef0169d6674b1a0e36a5e69969fae44386ea162c0a58c9f2389c68ff6dccfa17997b71ed7a29fafa1188be0bb615a569ceaea4f772bca4ac1222
7
+ data.tar.gz: 47736e485827ed67c73f8cbad6e163b37f7c1e8e665f5eca42daf698143de99adc24974e5849ef77d049299f3bfaca6ebb2051cfece0fe4a1a2ef9f94deb6ca8
@@ -0,0 +1,24 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ id-token: write
12
+
13
+ jobs:
14
+ release:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v5
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: '3.4'
22
+ bundler-cache: true
23
+ - name: Publish to RubyGems (trusted publishing)
24
+ uses: rubygems/release-gem@v1.1.1
@@ -0,0 +1,77 @@
1
+ name: Test
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches: [ main, master ]
7
+ pull_request:
8
+ branches: [ main, master ]
9
+ schedule:
10
+ - cron: "0 0 * * 0"
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: test-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ test:
21
+ strategy:
22
+ matrix:
23
+ ruby: ["3.2", "3.3", "3.4"]
24
+ activemodel: ["~> 7.2", "~> 8.0"]
25
+ runs-on: ubuntu-latest
26
+
27
+ steps:
28
+ - uses: actions/checkout@v5
29
+ - name: Set up Environment Variables
30
+ run: |
31
+ echo "ACTIVEMODEL_VERSION=${{ matrix.activemodel }}" >> $GITHUB_ENV
32
+
33
+ - name: Set up Ruby
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{ matrix.ruby }}
37
+ bundler-cache: false
38
+ - name: Prepare Gemfile for matrix
39
+ run: |
40
+ bundle config set frozen false
41
+ bundle lock --add-platform ruby --add-platform x86_64-linux || true
42
+ if [ -n "${{ matrix.activemodel }}" ]; then
43
+ bundle lock --update activemodel || true
44
+ fi
45
+ - name: Install dependencies
46
+ run: bundle install --jobs 4 --retry 1
47
+
48
+ - name: Run tests
49
+ run: bundle exec rake test
50
+
51
+ ar_integration:
52
+ strategy:
53
+ matrix:
54
+ ruby: ["3.2", "3.3", "3.4"]
55
+ activerecord: ["~> 7.2", "~> 8.0"]
56
+ runs-on: ubuntu-latest
57
+
58
+ steps:
59
+ - uses: actions/checkout@v5
60
+ - name: Set up Environment Variables
61
+ run: |
62
+ echo "AR_INTEGRATION=1" >> $GITHUB_ENV
63
+ echo "ACTIVERECORD_VERSION=${{ matrix.activerecord }}" >> $GITHUB_ENV
64
+ - name: Set up Ruby
65
+ uses: ruby/setup-ruby@v1
66
+ with:
67
+ ruby-version: ${{ matrix.ruby }}
68
+ bundler-cache: false
69
+ - name: Prepare Gemfile for AR matrix
70
+ run: |
71
+ bundle config set frozen false
72
+ bundle lock --add-platform ruby --add-platform x86_64-linux || true
73
+ bundle lock --update activerecord sqlite3 || true
74
+ - name: Install dependencies
75
+ run: bundle install --jobs 4 --retry 1
76
+ - name: Run integration tests
77
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ /vendor/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.3
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.10
7
+ before_install: gem install bundler -v 1.17.2
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Allow CI to pin a specific ActiveModel version via env var
6
+ am_ver = ENV["ACTIVEMODEL_VERSION"]
7
+ gem "activemodel", am_ver if am_ver
8
+
9
+ # Optional: ActiveRecord integration testing
10
+ if ENV["AR_INTEGRATION"] == "1"
11
+ ar_ver = ENV["ACTIVERECORD_VERSION"]
12
+ gem "activerecord", ar_ver || ">= 7.0", "< 9"
13
+ sqlite_req = (ar_ver && ar_ver.start_with?("~> 8")) ? ">= 2.1" : ">= 1.6"
14
+ gem "sqlite3", sqlite_req
15
+ end
16
+
17
+ # Specify your gem's dependencies in activerecord-s3-bucket-name-validator.gemspec
18
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ activerecord-s3-bucket-name-validator (0.1.0)
5
+ activemodel (>= 7.0, < 9)
6
+ i18n (>= 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (8.0.3)
12
+ activesupport (= 8.0.3)
13
+ activesupport (8.0.3)
14
+ base64
15
+ benchmark (>= 0.3)
16
+ bigdecimal
17
+ concurrent-ruby (~> 1.0, >= 1.3.1)
18
+ connection_pool (>= 2.2.5)
19
+ drb
20
+ i18n (>= 1.6, < 2)
21
+ logger (>= 1.4.2)
22
+ minitest (>= 5.1)
23
+ securerandom (>= 0.3)
24
+ tzinfo (~> 2.0, >= 2.0.5)
25
+ uri (>= 0.13.1)
26
+ base64 (0.3.0)
27
+ benchmark (0.4.1)
28
+ bigdecimal (3.2.3)
29
+ concurrent-ruby (1.3.5)
30
+ connection_pool (2.5.4)
31
+ drb (2.2.3)
32
+ i18n (1.14.7)
33
+ concurrent-ruby (~> 1.0)
34
+ logger (1.7.0)
35
+ minitest (5.25.5)
36
+ rake (13.3.0)
37
+ securerandom (0.4.1)
38
+ tzinfo (2.0.6)
39
+ concurrent-ruby (~> 1.0)
40
+ uri (1.0.3)
41
+
42
+ PLATFORMS
43
+ arm64-darwin-24
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ activerecord-s3-bucket-name-validator!
48
+ bundler (>= 1.17)
49
+ minitest (>= 5.0)
50
+ rake (>= 10.0)
51
+
52
+ BUNDLED WITH
53
+ 2.6.7
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Claudio Poli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # ActiveModel S3 Bucket Name Validator
2
+
3
+ ActiveModel validator for Amazon S3 bucket names. It implements the official AWS naming rules for:
4
+ - General purpose buckets (classic S3)
5
+ - Directory buckets (S3 Express One Zone)
6
+ - S3 Tables buckets
7
+
8
+ Works in any class using ActiveModel::Validations and in Rails/ActiveRecord models. Ships with i18n messages in multiple locales.
9
+
10
+ ## Installation
11
+
12
+ Add to your Gemfile:
13
+
14
+ ```ruby
15
+ gem "activerecord-s3-bucket-name-validator"
16
+ ```
17
+
18
+ Then bundle:
19
+
20
+ ```bash
21
+ bundle install
22
+ ```
23
+
24
+ ## Compatibility
25
+
26
+ - Ruby: 3.1, 3.2, 3.3, 3.4 (CI runs 3.2–3.4)
27
+ - ActiveModel: 7.2, 8.0 (CI targets)
28
+ - Rails/ActiveRecord: supported via ActiveModel::Validations (no Rails runtime dependency)
29
+
30
+ ## Quickstart
31
+
32
+ Plain ActiveModel:
33
+
34
+ ```ruby
35
+ class StorageConfig
36
+ include ActiveModel::Model
37
+ attr_accessor :bucket_name
38
+ validates :bucket_name, s3_bucket_name: true
39
+ end
40
+ ```
41
+
42
+ ActiveRecord model:
43
+
44
+ ```ruby
45
+ class Storage < ApplicationRecord
46
+ validates :bucket_name, s3_bucket_name: true
47
+ end
48
+ ```
49
+
50
+ ## Options
51
+
52
+ - `type` — `:general_purpose` (default), `:directory`, or `:table`
53
+ - `transfer_acceleration` — when `true`, periods are forbidden for general-purpose buckets
54
+
55
+ Examples:
56
+
57
+ ```ruby
58
+ validates :bucket_name, s3_bucket_name: { transfer_acceleration: true }
59
+ validates :bucket_name, s3_bucket_name: { type: :directory }
60
+ validates :bucket_name, s3_bucket_name: { type: :table }
61
+ ```
62
+
63
+ ## i18n
64
+
65
+ Error keys provided:
66
+ - `activemodel.errors.messages.s3_bucket_name_invalid_general`
67
+ - `activemodel.errors.messages.s3_bucket_name_invalid_transfer_acceleration`
68
+ - `activemodel.errors.messages.s3_bucket_name_invalid_directory`
69
+ - `activemodel.errors.messages.s3_bucket_name_invalid_table`
70
+
71
+ Locales shipped: en, es, it, fr, de, pt-BR, ja, ko, zh-CN, zh-TW, ru, nl.
72
+
73
+ Rails loads locales via a Railtie; plain ActiveModel loads them at require-time. Override by adding your own YAML with the same keys.
74
+
75
+ ## What’s validated (high level)
76
+
77
+ - Length 3–63, allowed characters, begin/end alphanumeric
78
+ - No adjacent periods; not IP-like (general purpose)
79
+ - Reserved prefixes/suffixes per AWS docs (for example `xn--`, `sthree-`, `amzn-s3-demo-`, `-s3alias`, `--ol-s3`, `.mrap`, `--x-s3`, `--table-s3`)
80
+ - Directory buckets must end with `--<zone-id>--x-s3`
81
+ - S3 Tables buckets disallow periods and underscores
82
+ - Optional TA mode forbids periods
83
+
84
+ Note: Global/partition uniqueness and immutability are service-side constraints and not enforced locally.
85
+
86
+ ## Examples
87
+
88
+ Valid (general purpose):
89
+
90
+ ```text
91
+ my-example-bucket
92
+ example.com
93
+ ```
94
+
95
+ Invalid (general purpose):
96
+
97
+ ```text
98
+ ex..ample
99
+ 192.168.5.4
100
+ xn--abc
101
+ foo--x-s3
102
+ ```
103
+
104
+ ## Running tests (for contributors)
105
+
106
+ ```bash
107
+ # ActiveModel-only
108
+ bundle install
109
+ bundle exec rake test
110
+
111
+ # With ActiveRecord integration (in-memory sqlite)
112
+ AR_INTEGRATION=1 ACTIVERECORD_VERSION="~> 8.0" bundle install
113
+ AR_INTEGRATION=1 ACTIVERECORD_VERSION="~> 8.0" bundle exec rake test
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT — see `LICENSE.txt`.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,49 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "activerecord/s3/bucket/name/validator/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "activerecord-s3-bucket-name-validator"
8
+ spec.version = Activerecord::S3::Bucket::Name::Validator::VERSION
9
+ spec.authors = ["Claudio Poli"]
10
+ spec.email = ["masterkain@gmail.com"]
11
+
12
+ spec.summary = %q{ActiveModel/ActiveRecord validator for Amazon S3 bucket naming rules}
13
+ spec.description = %q{Validate S3 bucket names on your models against the official AWS rules (general purpose, directory buckets, and S3 Tables).}
14
+ spec.homepage = "https://example.com/activerecord-s3-bucket-name-validator"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ # spec.metadata["source_code_uri"] = "https://example.com/activerecord-s3-bucket-name-validator"
24
+ # spec.metadata["changelog_uri"] = "https://example.com/activerecord-s3-bucket-name-validator/CHANGELOG.md"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.required_ruby_version = ">= 3.1"
40
+
41
+ # Runtime dependencies
42
+ spec.add_dependency "activemodel", ">= 7.0", "< 9"
43
+ spec.add_dependency "i18n", ">= 1.0"
44
+
45
+ # Development and test dependencies
46
+ spec.add_development_dependency "bundler", ">= 1.17"
47
+ spec.add_development_dependency "rake", ">= 10.0"
48
+ spec.add_development_dependency "minitest", ">= 5.0"
49
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "activerecord/s3/bucket/name/validator"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,9 @@
1
+ de:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "ist kein gültiger S3-Bucket-Name (3–63 Zeichen; Kleinbuchstaben, Ziffern, Punkte oder Bindestriche; beginnt/endet alphanumerisch; kein '..'; keine IP-ähnlichen Namen; keine reservierten Präfixe/Suffixe)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "darf keine Punkte enthalten, wenn S3 Transfer Acceleration verwendet wird"
7
+ s3_bucket_name_invalid_directory: "ist kein gültiger S3-Verzeichnis-Bucket-Name (3–63 Zeichen; Kleinbuchstaben, Ziffern oder Bindestriche; muss mit --<zone-id>--x-s3 enden; reservierte Präfixe/Suffixe nicht erlaubt)"
8
+ s3_bucket_name_invalid_table: "ist kein gültiger S3-Tables-Bucket-Name (3–63 Zeichen; Kleinbuchstaben, Ziffern oder Bindestriche; keine Punkte oder Unterstriche; keine reservierten Präfixe/Suffixe)"
9
+ s3_bucket_name_invalid: "ist kein gültiger S3-Bucket-Name"
@@ -0,0 +1,9 @@
1
+ en:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "is not a valid S3 bucket name (3–63 chars; lowercase letters, numbers, periods or hyphens; start/end alphanumeric; no '..'; not IP-like; no reserved prefixes/suffixes)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "cannot contain periods when using S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "is not a valid S3 directory bucket name (3–63 chars; lowercase letters, numbers or hyphens; must end with --<zone-id>--x-s3; reserved prefixes/suffixes not allowed)"
8
+ s3_bucket_name_invalid_table: "is not a valid S3 Tables bucket name (3–63 chars; lowercase letters, numbers or hyphens; no periods or underscores; reserved prefixes/suffixes not allowed)"
9
+ s3_bucket_name_invalid: "is not a valid S3 bucket name"
@@ -0,0 +1,9 @@
1
+ es:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "no es un nombre de bucket S3 válido (3–63 caracteres; letras minúsculas, números, puntos o guiones; empieza y termina alfanumérico; sin '..'; no con formato IP; sin prefijos/sufijos reservados)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "no puede contener puntos cuando se usa S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "no es un nombre de bucket de directorio S3 válido (3–63 caracteres; letras minúsculas, números o guiones; debe terminar con --<zone-id>--x-s3; prefijos/sufijos reservados no permitidos)"
8
+ s3_bucket_name_invalid_table: "no es un nombre de bucket S3 Tables válido (3–63 caracteres; letras minúsculas, números o guiones; sin puntos ni guiones bajos; sin prefijos/sufijos reservados)"
9
+ s3_bucket_name_invalid: "no es un nombre de bucket S3 válido"
@@ -0,0 +1,9 @@
1
+ fr:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "n’est pas un nom de bucket S3 valide (3–63 caractères ; lettres minuscules, chiffres, points ou tirets ; commence et se termine par un caractère alphanumérique ; pas de '..' ; ne doit pas ressembler à une adresse IP ; pas de préfixes/suffixes réservés)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "ne peut pas contenir de points avec S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "n’est pas un nom de bucket de répertoire S3 valide (3–63 caractères ; lettres minuscules, chiffres ou tirets ; doit se terminer par --<zone-id>--x-s3 ; préfixes/suffixes réservés interdits)"
8
+ s3_bucket_name_invalid_table: "n’est pas un nom de bucket S3 Tables valide (3–63 caractères ; lettres minuscules, chiffres ou tirets ; sans points ni underscores ; pas de préfixes/suffixes réservés)"
9
+ s3_bucket_name_invalid: "n’est pas un nom de bucket S3 valide"
@@ -0,0 +1,9 @@
1
+ it:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "non è un nome bucket S3 valido (3–63 caratteri; lettere minuscole, numeri, punti o trattini; inizia/termina alfanumerico; senza '..'; non in formato IP; senza prefissi/suffissi riservati)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "non può contenere punti quando si usa S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "non è un nome bucket directory S3 valido (3–63 caratteri; lettere minuscole, numeri o trattini; deve terminare con --<zone-id>--x-s3; prefissi/suffissi riservati non consentiti)"
8
+ s3_bucket_name_invalid_table: "non è un nome bucket S3 Tables valido (3–63 caratteri; lettere minuscole, numeri o trattini; senza punti o underscore; senza prefissi/suffissi riservati)"
9
+ s3_bucket_name_invalid: "non è un nome bucket S3 valido"
@@ -0,0 +1,9 @@
1
+ ja:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "有効な S3 バケット名ではありません(3~63 文字、小文字の英字・数字・ピリオド・ハイフン、先頭/末尾は英数字、'..' 不可、IP 形式不可、予約済みの接頭/接尾辞不可)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "S3 Transfer Acceleration を使用する場合、ピリオドは使用できません"
7
+ s3_bucket_name_invalid_directory: "有効な S3 ディレクトリバケット名ではありません(3~63 文字、小文字の英字・数字・ハイフン、末尾に --<zone-id>--x-s3 必須、予約済みの接頭/接尾辞不可)"
8
+ s3_bucket_name_invalid_table: "有効な S3 Tables バケット名ではありません(3~63 文字、小文字の英字・数字・ハイフン、ピリオドおよびアンダースコア不可、予約済みの接頭/接尾辞不可)"
9
+ s3_bucket_name_invalid: "有効な S3 バケット名ではありません"
@@ -0,0 +1,9 @@
1
+ ko:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "유효한 S3 버킷 이름이 아닙니다(3–63자; 소문자, 숫자, 점 또는 하이픈; 시작/끝은 영숫자; '..' 금지; IP 형식 금지; 예약된 접두사/접미사 금지)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "S3 Transfer Acceleration 사용 시 점(.)을 포함할 수 없습니다"
7
+ s3_bucket_name_invalid_directory: "유효한 S3 디렉터리 버킷 이름이 아닙니다(3–63자; 소문자, 숫자 또는 하이픈; '--<zone-id>--x-s3'로 끝나야 함; 예약된 접두사/접미사 금지)"
8
+ s3_bucket_name_invalid_table: "유효한 S3 Tables 버킷 이름이 아닙니다(3–63자; 소문자, 숫자 또는 하이픈; 점/밑줄 금지; 예약된 접두사/접미사 금지)"
9
+ s3_bucket_name_invalid: "유효한 S3 버킷 이름이 아닙니다"
@@ -0,0 +1,9 @@
1
+ nl:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "is geen geldige S3-bucketnaam (3–63 tekens; kleine letters, cijfers, punten of koppeltekens; begint/eindigt alfanumerisch; geen '..'; geen IP-formaat; geen gereserveerde voor-/achtervoegsels)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "mag geen punten bevatten wanneer S3 Transfer Acceleration wordt gebruikt"
7
+ s3_bucket_name_invalid_directory: "is geen geldige S3-directorybucketnaam (3–63 tekens; kleine letters, cijfers of koppeltekens; moet eindigen op --<zone-id>--x-s3; gereserveerde voor-/achtervoegsels niet toegestaan)"
8
+ s3_bucket_name_invalid_table: "is geen geldige S3 Tables-bucketnaam (3–63 tekens; kleine letters, cijfers of koppeltekens; geen punten of underscores; geen gereserveerde voor-/achtervoegsels)"
9
+ s3_bucket_name_invalid: "is geen geldige S3-bucketnaam"
@@ -0,0 +1,9 @@
1
+ pt-BR:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "não é um nome de bucket S3 válido (3–63 caracteres; letras minúsculas, números, pontos ou hífens; começa/termina alfanumérico; sem '..'; não no formato de IP; sem prefixos/sufixos reservados)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "não pode conter pontos ao usar S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "não é um nome de bucket de diretório S3 válido (3–63 caracteres; letras minúsculas, números ou hífens; deve terminar com --<zone-id>--x-s3; prefixos/sufixos reservados não permitidos)"
8
+ s3_bucket_name_invalid_table: "não é um nome de bucket S3 Tables válido (3–63 caracteres; letras minúsculas, números ou hífens; sem pontos ou underscores; sem prefixos/sufixos reservados)"
9
+ s3_bucket_name_invalid: "não é um nome de bucket S3 válido"
@@ -0,0 +1,9 @@
1
+ ru:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "недопустимое имя S3 бакета (3–63 символа; строчные буквы, цифры, точки или дефисы; начинается/заканчивается буквенно-цифровым символом; без '..'; не должно быть похоже на IP; без зарезервированных префиксов/суффиксов)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "нельзя использовать точки при S3 Transfer Acceleration"
7
+ s3_bucket_name_invalid_directory: "недопустимое имя каталожного S3 бакета (3–63 символа; строчные буквы, цифры или дефисы; должно заканчиваться на --<zone-id>--x-s3; зарезервированные префиксы/суффиксы запрещены)"
8
+ s3_bucket_name_invalid_table: "недопустимое имя бакета S3 Tables (3–63 символа; строчные буквы, цифры или дефисы; без точек и нижних подчёркиваний; зарезервированные префиксы/суффиксы запрещены)"
9
+ s3_bucket_name_invalid: "недопустимое имя S3 бакета"
@@ -0,0 +1,9 @@
1
+ zh-CN:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "不是有效的 S3 存储桶名称(3–63 个字符;小写字母、数字、点或连字符;首尾必须为字母或数字;不允许 '..';不得为 IP 格式;不得使用保留的前缀/后缀)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "使用 S3 Transfer Acceleration 时,名称中不能包含点(.)"
7
+ s3_bucket_name_invalid_directory: "不是有效的 S3 目录存储桶名称(3–63 个字符;小写字母、数字或连字符;必须以 --<zone-id>--x-s3 结尾;不得使用保留的前缀/后缀)"
8
+ s3_bucket_name_invalid_table: "不是有效的 S3 Tables 存储桶名称(3–63 个字符;小写字母、数字或连字符;不允许点或下划线;不得使用保留的前缀/后缀)"
9
+ s3_bucket_name_invalid: "不是有效的 S3 存储桶名称"
@@ -0,0 +1,9 @@
1
+ zh-TW:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ s3_bucket_name_invalid_general: "不是有效的 S3 儲存貯體名稱(3–63 個字元;小寫字母、數字、點或連字號;開頭與結尾必須為英數字;不可含 '..';不得為 IP 格式;不得使用保留的前/後綴)"
6
+ s3_bucket_name_invalid_transfer_acceleration: "使用 S3 Transfer Acceleration 時,名稱中不可包含點(.)"
7
+ s3_bucket_name_invalid_directory: "不是有效的 S3 目錄儲存貯體名稱(3–63 個字元;小寫字母、數字或連字號;必須以 --<zone-id>--x-s3 結尾;不得使用保留的前/後綴)"
8
+ s3_bucket_name_invalid_table: "不是有效的 S3 Tables 儲存貯體名稱(3–63 個字元;小寫字母、數字或連字號;不可有點或底線;不得使用保留的前/後綴)"
9
+ s3_bucket_name_invalid: "不是有效的 S3 儲存貯體名稱"
@@ -0,0 +1,19 @@
1
+ require "rails/railtie"
2
+
3
+ module Activerecord
4
+ module S3
5
+ module Bucket
6
+ module Name
7
+ module Validator
8
+ class Railtie < ::Rails::Railtie
9
+ initializer "activerecord-s3-bucket-name-validator.i18n" do |app|
10
+ locales = Dir[File.expand_path("../../../../../config/locales/*.yml", __FILE__)]
11
+ app.config.i18n.load_path.concat(locales)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,11 @@
1
+ module Activerecord
2
+ module S3
3
+ module Bucket
4
+ module Name
5
+ module Validator
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,125 @@
1
+ require "activerecord/s3/bucket/name/validator/version"
2
+ require "active_model"
3
+ require "i18n"
4
+ begin
5
+ require "activerecord/s3/bucket/name/validator/railtie"
6
+ rescue LoadError
7
+ # Rails not present; ignore
8
+ end
9
+
10
+ module Activerecord
11
+ module S3
12
+ module Bucket
13
+ module Name
14
+ module Validator
15
+ # Validator implementation lives at top-level constant so Rails can autoload it
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ # Load embedded translations when not in Rails (Rails will pick them up via Railtie below)
23
+ begin
24
+ locales_glob = File.expand_path("../../../../../config/locales/*.yml", __FILE__)
25
+ I18n.load_path += Dir[locales_glob] if Dir.exist?(File.dirname(locales_glob))
26
+ rescue StandardError
27
+ # ignore i18n loading errors
28
+ end
29
+
30
+ # Usage in a model:
31
+ # validates :bucket_name, s3_bucket_name: { type: :general_purpose }
32
+ # Options:
33
+ # :type => :general_purpose (default), :directory, or :table
34
+ # :transfer_acceleration => true to forbid periods for TA buckets
35
+ class S3BucketNameValidator < ActiveModel::EachValidator
36
+ RESERVED_PREFIXES_GENERAL = %w[xn-- sthree- amzn-s3-demo-].freeze
37
+ RESERVED_SUFFIXES_GENERAL = %w[-s3alias --ol-s3 .mrap --x-s3 --table-s3].freeze
38
+
39
+ RESERVED_PREFIXES_TABLE = %w[xn-- sthree- amzn-s3-demo- aws].freeze
40
+ RESERVED_SUFFIXES_TABLE = %w[-s3alias --ol-s3 --x-s3 --table-s3].freeze
41
+
42
+ def validate_each(record, attribute, value)
43
+ type = (options[:type] || :general_purpose).to_sym
44
+ return if blank_ok?(value)
45
+
46
+ valid = case type
47
+ when :general_purpose then validate_general_purpose(value, transfer_acceleration: !!options[:transfer_acceleration])
48
+ when :directory then validate_directory_bucket(value)
49
+ when :table then validate_table_bucket(value)
50
+ else
51
+ record.errors.add(attribute, :invalid, message: "unknown bucket type: #{type}")
52
+ false
53
+ end
54
+
55
+ unless valid
56
+ error_key = if type == :general_purpose && options[:transfer_acceleration] && value.include?(".")
57
+ :s3_bucket_name_invalid_transfer_acceleration
58
+ else
59
+ case type
60
+ when :general_purpose then :s3_bucket_name_invalid_general
61
+ when :directory then :s3_bucket_name_invalid_directory
62
+ when :table then :s3_bucket_name_invalid_table
63
+ else :s3_bucket_name_invalid
64
+ end
65
+ end
66
+ record.errors.add(attribute, error_key)
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ # I18n error messages are defined in config/locales/*.yml
73
+
74
+ def blank_ok?(value)
75
+ value.nil? || (value.respond_to?(:empty?) && value.empty?)
76
+ end
77
+
78
+ # Based on AWS docs: General purpose bucket naming rules
79
+ def validate_general_purpose(name, transfer_acceleration: false)
80
+ return false unless length_between?(name, 3, 63)
81
+ return false unless name =~ /\A[a-z0-9.-]+\z/
82
+ return false unless begins_and_ends_with_alnum?(name)
83
+ return false if name.include?("..")
84
+ return false if ip_like?(name)
85
+ return false unless RESERVED_PREFIXES_GENERAL.none? { |p| name.start_with?(p) }
86
+ return false unless RESERVED_SUFFIXES_GENERAL.none? { |s| name.end_with?(s) }
87
+ return false if transfer_acceleration && name.include?(".")
88
+ true
89
+ end
90
+
91
+ # Based on AWS docs: Directory bucket naming rules (S3 Express One Zone)
92
+ def validate_directory_bucket(name)
93
+ return false unless length_between?(name, 3, 63)
94
+ return false unless name =~ /\A[a-z0-9-]+\z/
95
+ return false unless begins_and_ends_with_alnum?(name)
96
+ # must contain --<zone-id>--x-s3 suffix
97
+ return false unless name =~ /--[a-z0-9-]+--x-s3\z/
98
+ # reserved prefixes/suffixes still apply
99
+ return false if name.start_with?("xn--", "sthree-", "sthree-configurator", "amzn-s3-demo-")
100
+ return false if name.end_with?("-s3alias", "--ol-s3", ".mrap", "--table-s3")
101
+ true
102
+ end
103
+
104
+ # Based on AWS docs: S3 Tables bucket naming rules
105
+ def validate_table_bucket(name)
106
+ return false unless length_between?(name, 3, 63)
107
+ return false unless name =~ /\A[a-z0-9-]+\z/
108
+ return false unless begins_and_ends_with_alnum?(name)
109
+ return false unless RESERVED_PREFIXES_TABLE.none? { |p| name.start_with?(p) }
110
+ return false unless RESERVED_SUFFIXES_TABLE.none? { |s| name.end_with?(s) }
111
+ true
112
+ end
113
+
114
+ def length_between?(str, min, max)
115
+ str.length.between?(min, max)
116
+ end
117
+
118
+ def begins_and_ends_with_alnum?(str)
119
+ str[0] =~ /[a-z0-9]/ && str[-1] =~ /[a-z0-9]/
120
+ end
121
+
122
+ def ip_like?(str)
123
+ str =~ /\A(?:\d{1,3}\.){3}\d{1,3}\z/
124
+ end
125
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-s3-bucket-name-validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Claudio Poli
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activemodel
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9'
32
+ - !ruby/object:Gem::Dependency
33
+ name: i18n
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '1.0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '1.17'
53
+ type: :development
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '1.17'
60
+ - !ruby/object:Gem::Dependency
61
+ name: rake
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '10.0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '10.0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: minitest
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '5.0'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '5.0'
88
+ description: Validate S3 bucket names on your models against the official AWS rules
89
+ (general purpose, directory buckets, and S3 Tables).
90
+ email:
91
+ - masterkain@gmail.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - ".github/workflows/release.yaml"
97
+ - ".github/workflows/test.yml"
98
+ - ".gitignore"
99
+ - ".ruby-version"
100
+ - ".travis.yml"
101
+ - Gemfile
102
+ - Gemfile.lock
103
+ - LICENSE.txt
104
+ - README.md
105
+ - Rakefile
106
+ - activerecord-s3-bucket-name-validator.gemspec
107
+ - bin/console
108
+ - bin/setup
109
+ - config/locales/de.yml
110
+ - config/locales/en.yml
111
+ - config/locales/es.yml
112
+ - config/locales/fr.yml
113
+ - config/locales/it.yml
114
+ - config/locales/ja.yml
115
+ - config/locales/ko.yml
116
+ - config/locales/nl.yml
117
+ - config/locales/pt-BR.yml
118
+ - config/locales/ru.yml
119
+ - config/locales/zh-CN.yml
120
+ - config/locales/zh-TW.yml
121
+ - lib/activerecord/s3/bucket/name/validator.rb
122
+ - lib/activerecord/s3/bucket/name/validator/railtie.rb
123
+ - lib/activerecord/s3/bucket/name/validator/version.rb
124
+ homepage: https://example.com/activerecord-s3-bucket-name-validator
125
+ licenses:
126
+ - MIT
127
+ metadata:
128
+ homepage_uri: https://example.com/activerecord-s3-bucket-name-validator
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '3.1'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.6.9
144
+ specification_version: 4
145
+ summary: ActiveModel/ActiveRecord validator for Amazon S3 bucket naming rules
146
+ test_files: []