wsaa-ruby 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 398c92ee7bbeb19908d73033e371a8ee15c20e981eb377b26eccfa260d51c410
4
- data.tar.gz: 7396411b2096967bd3113d77357b91c92bf64c41cc673993aa74bf2b1843ffd1
3
+ metadata.gz: 44235acd9e7f8d3e11e4219e44930fb679efc89c4212b07d236742cbe51001be
4
+ data.tar.gz: 967d77aedffe2e5a2700bd6730c1cc960eac4157d871cfe88c49e8c288fb3000
5
5
  SHA512:
6
- metadata.gz: 0335726e838104a2738869286ff3da6e5ec5fc128d8ea3f23094c624b9ccbcf95363cdb09502097210fa970fbe1fc86b618058be773e780c84afff45e57dbec0
7
- data.tar.gz: 79beb07a9f78bc8ff61ae4e8f2d6508417de9903e02c92c835e998710035b7a36a09d3e00a5d0a88b6fac9cb05c7e64fec1e1877369edf00b34658810451ad44
6
+ metadata.gz: 2cc847451d29f43e4b1146f55117678b5939cb66fa205d89e99f0a7adf3aa2e7e00b77e1611c4a319026632f08d5ba9d150763491bd2e45c131661da7b639102
7
+ data.tar.gz: afc68f5f8c0fbdc7b711f81e5e4c4c070480879334ce70cf30e54eb64d5231b116469017f0fb6b45eb46562a870c06eea5ff79d3268f317eab3c3e6665dd5011
data/AGENTS.md ADDED
@@ -0,0 +1,124 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code when working with code in this repository.
4
+
5
+ ## Writing Convention
6
+
7
+ Use ASD-STE100 (Simplified Technical English) for all communication:
8
+
9
+ - Write short sentences (20 words maximum)
10
+ - Use active voice
11
+ - Use approved vocabulary only
12
+ - Use one meaning per word
13
+ - Write instructions as commands
14
+
15
+ ## Coding Conventions
16
+
17
+ ### RDoc Documentation
18
+
19
+ Add RDoc comments to all public classes and methods. Follow this format:
20
+
21
+ ```ruby
22
+ ##
23
+ # Short description of the class or method.
24
+ #
25
+ # @param name [Type] Description of the parameter.
26
+ # @return [Type] Description of the return value.
27
+ # @raise [ErrorClass] Description of when this error occurs.
28
+ #
29
+ # @example
30
+ # result = method_name(arg)
31
+ # # => expected output
32
+ ```
33
+
34
+ Apply this requirement to all new code and modified code.
35
+
36
+ ### Git Commits
37
+
38
+ - Make commits atomic: include only one coherent change or fix
39
+ - Do not mix unrelated work in a single commit
40
+ - Write succinct commit messages that describe the change
41
+ - Add both co-authors to each commit message:
42
+ ```
43
+ Co-Authored-By: Leandro Marcucci <leanucci@gmail.com>
44
+ Co-Authored-By: Claude <noreply@anthropic.com>
45
+ ```
46
+
47
+ ## Project Overview
48
+
49
+ wsaa-ruby is a Ruby gem for authenticating with AFIP's WSAA (Web Service de Autenticación y Autorización). It handles the login process to obtain TOKEN and SIGN credentials needed to call other AFIP services like WSFE (electronic invoicing).
50
+
51
+ ## Build & Test Commands
52
+
53
+ ```bash
54
+ bundle install # Install dependencies
55
+ bundle exec rspec # Run all RSpec tests
56
+ bundle exec rake # Run default task (specs)
57
+ ```
58
+
59
+ Run a single test file:
60
+ ```bash
61
+ bundle exec rspec spec/wsaa/client_spec.rb
62
+ ```
63
+
64
+ ## Required Environment
65
+
66
+ - Ruby >= 2.7.0 (see gemspec)
67
+ - Valid AFIP X.509 certificate and private key
68
+ - Certificate must be registered with AFIP for the target service
69
+
70
+ ## Architecture
71
+
72
+ ### Core Classes
73
+
74
+ - **`Wsaa`** (`lib/wsaa.rb`) - Main module with configuration and authentication entry points
75
+ - **`Wsaa::Client`** (`lib/wsaa/client.rb`) - Orchestrates the authentication flow
76
+ - **`Wsaa::Tra`** (`lib/wsaa/tra.rb`) - Builds the Ticket de Requerimiento de Acceso XML
77
+ - **`Wsaa::CmsSigner`** (`lib/wsaa/cms_signer.rb`) - Signs TRA using OpenSSL PKCS#7
78
+ - **`Wsaa::Credentials`** (`lib/wsaa/credentials.rb`) - Immutable value object for TOKEN/SIGN
79
+ - **`Wsaa::CredentialStore`** (`lib/wsaa/credential_store.rb`) - File-based credential caching
80
+ - **`Wsaa::Configuration`** (`lib/wsaa/configuration.rb`) - Configuration with validation
81
+ - **`Wsaa::Errors`** (`lib/wsaa/errors.rb`) - Custom exceptions
82
+
83
+ ### Authentication Flow
84
+
85
+ 1. `Wsaa.authenticate` checks for cached credentials in `CredentialStore`
86
+ 2. If no valid cache, builds TRA XML with service name and time boundaries
87
+ 3. Signs TRA using CMS/PKCS#7 with certificate and private key
88
+ 4. Calls WSAA `loginCms` SOAP operation via Savon
89
+ 5. Parses response to extract TOKEN and SIGN
90
+ 6. Caches credentials for reuse until expiration
91
+
92
+ ### SOAP Communication
93
+
94
+ Uses Savon ~> 2.0 for AFIP web services:
95
+ - **Testing (Homologación)**: `https://wsaahomo.afip.gov.ar/ws/services/LoginCms`
96
+ - **Production**: `https://wsaa.afip.gov.ar/ws/services/LoginCms`
97
+
98
+ ## Usage Example
99
+
100
+ ```ruby
101
+ require 'wsaa'
102
+
103
+ Wsaa.configure do |config|
104
+ config.pkey = 'path/to/private_key'
105
+ config.cert = 'path/to/certificate'
106
+ config.service = 'wsfe'
107
+ config.environment = :testing # or :production
108
+ end
109
+
110
+ credentials = Wsaa.authenticate
111
+ credentials.token # => "PD94bWwg..."
112
+ credentials.sign # => "GGG2XMe..."
113
+ ```
114
+
115
+ ## Key Dependencies
116
+
117
+ - **savon** (~> 2.0) - SOAP client
118
+ - **rack** (~> 2.0) - Pinned for httpi compatibility
119
+ - **openssl** - Ruby stdlib, for PKCS#7 signing
120
+ - **rexml** - Ruby stdlib, for XML building
121
+
122
+ ## Documentation
123
+
124
+ - [WSAA Technical Specification (PDF)](https://www.afip.gov.ar/ws/WSAA/Especificacion_Tecnica_WSAA_1.2.0.pdf)
data/CHANGELOG.md CHANGED
@@ -7,5 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.1] - 2026-08-18
11
+
12
+ ### Fixed
13
+ - Replaced real credentials with dummy test fixtures
14
+
15
+ ### Security
16
+ - Removed accidentally committed credentials from git history
17
+
18
+ ## [0.2.0] - 2026-08-18
19
+
10
20
  ### Added
11
- - Initial gem structure
21
+ - RDoc documentation for all public classes and methods
22
+ - GitHub Actions CI workflow for running tests on PRs
23
+ - GitHub Actions release workflow for publishing to RubyGems
24
+
25
+ ## [0.1.0] - 2026-08-18
26
+
27
+ ### Added
28
+ - Initial gem structure (2026-07-30)
29
+ - WSAA authentication client with SOAP support
30
+ - TRA (Ticket de Requerimiento de Acceso) XML builder
31
+ - CMS/PKCS#7 signing with OpenSSL
32
+ - Credentials caching with file-based storage
33
+ - Configuration with testing and production endpoints
34
+ - RSpec test suite with 81 examples
35
+ - Agent configuration files (CLAUDE.md, AGENTS.md)
36
+
37
+ ### Published
38
+ - Released to RubyGems.org as wsaa-ruby 0.1.0
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
data/lib/wsaa/client.rb CHANGED
@@ -2,13 +2,29 @@ require 'savon'
2
2
  require 'rexml/document'
3
3
 
4
4
  module Wsaa
5
+ ##
6
+ # WSAA authentication client.
7
+ #
8
+ # Orchestrates the authentication flow: builds TRA, signs it, calls WSAA, and caches credentials.
9
+ #
10
+ # @attr_reader configuration [Configuration] The client configuration.
5
11
  class Client
6
12
  attr_reader :configuration
7
13
 
14
+ ##
15
+ # Creates a new Client.
16
+ #
17
+ # @param configuration [Configuration] The client configuration.
8
18
  def initialize(configuration)
9
19
  @configuration = configuration
10
20
  end
11
21
 
22
+ ##
23
+ # Authenticates with WSAA using cached credentials if available.
24
+ #
25
+ # @return [Credentials] The authentication credentials.
26
+ # @raise [ConfigurationError] If the configuration is invalid.
27
+ # @raise [AuthenticationError] If authentication fails.
12
28
  def authenticate
13
29
  configuration.validate!
14
30
 
@@ -18,6 +34,12 @@ module Wsaa
18
34
  authenticate!
19
35
  end
20
36
 
37
+ ##
38
+ # Authenticates with WSAA, ignoring any cached credentials.
39
+ #
40
+ # @return [Credentials] The authentication credentials.
41
+ # @raise [ConfigurationError] If the configuration is invalid.
42
+ # @raise [AuthenticationError] If authentication fails.
21
43
  def authenticate!
22
44
  configuration.validate!
23
45
 
@@ -2,14 +2,33 @@ require 'openssl'
2
2
  require 'base64'
3
3
 
4
4
  module Wsaa
5
+ ##
6
+ # Signs data using CMS/PKCS#7 format.
7
+ #
8
+ # Creates cryptographic signatures compatible with WSAA requirements.
9
+ #
10
+ # @attr_reader certificate [OpenSSL::X509::Certificate] The signing certificate.
11
+ # @attr_reader private_key [OpenSSL::PKey::RSA] The private key for signing.
5
12
  class CmsSigner
6
13
  attr_reader :certificate, :private_key
7
14
 
15
+ ##
16
+ # Creates a new CmsSigner.
17
+ #
18
+ # @param cert_path [String] Path to the certificate file in PEM format.
19
+ # @param pkey_path [String] Path to the private key file in PEM format.
20
+ # @raise [SigningError] If the certificate or key cannot be loaded.
8
21
  def initialize(cert_path:, pkey_path:)
9
22
  @certificate = load_certificate(cert_path)
10
23
  @private_key = load_private_key(pkey_path)
11
24
  end
12
25
 
26
+ ##
27
+ # Signs data and returns the base64-encoded CMS signature.
28
+ #
29
+ # @param data [String] The data to sign.
30
+ # @return [String] Base64-encoded PKCS#7/CMS signature.
31
+ # @raise [SigningError] If signing fails.
13
32
  def sign(data)
14
33
  flags = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::NOSMIMECAP
15
34
  pkcs7 = OpenSSL::PKCS7.sign(certificate, private_key, data, [], flags)
@@ -1,4 +1,12 @@
1
1
  module Wsaa
2
+ ##
3
+ # Holds configuration for the WSAA client.
4
+ #
5
+ # @attr_accessor pkey [String] Path to the private key file.
6
+ # @attr_accessor cert [String] Path to the certificate file.
7
+ # @attr_accessor service [String] The AFIP service to authenticate for.
8
+ # @attr_accessor environment [Symbol] The environment (:testing or :production).
9
+ # @attr_accessor cache_dir [String] Directory for credential caching.
2
10
  class Configuration
3
11
  ENDPOINTS = {
4
12
  testing: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',
@@ -7,18 +15,30 @@ module Wsaa
7
15
 
8
16
  attr_accessor :pkey, :cert, :service, :environment, :cache_dir
9
17
 
18
+ ##
19
+ # Creates a new Configuration with default values.
10
20
  def initialize
11
21
  @environment = :testing
12
22
  @service = 'wsfe'
13
23
  @cache_dir = '/tmp'
14
24
  end
15
25
 
26
+ ##
27
+ # Returns the WSAA endpoint URL for the current environment.
28
+ #
29
+ # @return [String] The endpoint URL.
30
+ # @raise [ConfigurationError] If the environment is invalid.
16
31
  def endpoint
17
32
  ENDPOINTS.fetch(environment) do
18
33
  raise ConfigurationError, "Invalid environment: #{environment}. Must be :testing or :production"
19
34
  end
20
35
  end
21
36
 
37
+ ##
38
+ # Validates the configuration.
39
+ #
40
+ # @return [true] If the configuration is valid.
41
+ # @raise [ConfigurationError] If required values are missing or files do not exist.
22
42
  def validate!
23
43
  raise ConfigurationError, "Private key path not configured" if pkey.nil? || pkey.empty?
24
44
  raise ConfigurationError, "Certificate path not configured" if cert.nil? || cert.empty?
@@ -2,14 +2,30 @@ require 'yaml'
2
2
  require 'time'
3
3
 
4
4
  module Wsaa
5
+ ##
6
+ # File-based cache for WSAA credentials.
7
+ #
8
+ # Stores credentials as YAML files with date-based filenames.
9
+ #
10
+ # @attr_reader cache_dir [String] Directory where cache files are stored.
11
+ # @attr_reader service [String] The service name used in the cache filename.
5
12
  class CredentialStore
6
13
  attr_reader :cache_dir, :service
7
14
 
15
+ ##
16
+ # Creates a new CredentialStore.
17
+ #
18
+ # @param cache_dir [String] Directory for cache files.
19
+ # @param service [String] The service name.
8
20
  def initialize(cache_dir:, service:)
9
21
  @cache_dir = cache_dir
10
22
  @service = service
11
23
  end
12
24
 
25
+ ##
26
+ # Reads cached credentials.
27
+ #
28
+ # @return [Credentials, nil] The cached credentials, or nil if not found or expired.
13
29
  def read
14
30
  return nil unless File.exist?(cache_file_path)
15
31
 
@@ -27,15 +43,26 @@ module Wsaa
27
43
  nil
28
44
  end
29
45
 
46
+ ##
47
+ # Writes credentials to the cache.
48
+ #
49
+ # @param credentials [Credentials] The credentials to cache.
50
+ # @return [Credentials] The same credentials object.
30
51
  def write(credentials)
31
52
  File.write(cache_file_path, YAML.dump(credentials.to_h.transform_keys(&:to_s)))
32
53
  credentials
33
54
  end
34
55
 
56
+ ##
57
+ # Deletes the cache file.
35
58
  def clear
36
59
  File.delete(cache_file_path) if File.exist?(cache_file_path)
37
60
  end
38
61
 
62
+ ##
63
+ # Returns the full path to the cache file.
64
+ #
65
+ # @return [String] The cache file path.
39
66
  def cache_file_path
40
67
  File.join(cache_dir, cache_filename)
41
68
  end
@@ -1,7 +1,21 @@
1
1
  module Wsaa
2
+ ##
3
+ # Immutable value object for WSAA authentication credentials.
4
+ #
5
+ # Holds the TOKEN and SIGN values returned by WSAA after successful authentication.
6
+ #
7
+ # @attr_reader token [String] The authentication token.
8
+ # @attr_reader sign [String] The authentication signature.
9
+ # @attr_reader expiration_time [Time] When the credentials expire.
2
10
  class Credentials
3
11
  attr_reader :token, :sign, :expiration_time
4
12
 
13
+ ##
14
+ # Creates new Credentials.
15
+ #
16
+ # @param token [String] The authentication token from WSAA.
17
+ # @param sign [String] The authentication signature from WSAA.
18
+ # @param expiration_time [Time] When the credentials expire.
5
19
  def initialize(token:, sign:, expiration_time:)
6
20
  @token = token.freeze
7
21
  @sign = sign.freeze
@@ -9,14 +23,26 @@ module Wsaa
9
23
  freeze
10
24
  end
11
25
 
26
+ ##
27
+ # Checks if the credentials have expired.
28
+ #
29
+ # @return [Boolean] True if expired.
12
30
  def expired?
13
31
  Time.now > expiration_time
14
32
  end
15
33
 
34
+ ##
35
+ # Checks if the credentials are valid.
36
+ #
37
+ # @return [Boolean] True if not expired and has token and sign.
16
38
  def valid?
17
39
  !expired? && !token.nil? && !sign.nil?
18
40
  end
19
41
 
42
+ ##
43
+ # Converts credentials to a hash.
44
+ #
45
+ # @return [Hash] Hash with :token, :sign, and :expiration_time keys.
20
46
  def to_h
21
47
  {
22
48
  token: token,
data/lib/wsaa/errors.rb CHANGED
@@ -1,13 +1,30 @@
1
1
  module Wsaa
2
+ ##
3
+ # Base error class for all WSAA errors.
2
4
  class Error < StandardError; end
3
5
 
6
+ ##
7
+ # Raised when the configuration is invalid or incomplete.
4
8
  class ConfigurationError < Error; end
5
9
 
10
+ ##
11
+ # Raised when CMS/PKCS#7 signing fails.
6
12
  class SigningError < Error; end
7
13
 
14
+ ##
15
+ # Raised when WSAA authentication fails.
16
+ #
17
+ # @attr_reader fault_code [String, nil] The SOAP fault code from WSAA.
18
+ # @attr_reader fault_string [String, nil] The SOAP fault message from WSAA.
8
19
  class AuthenticationError < Error
9
20
  attr_reader :fault_code, :fault_string
10
21
 
22
+ ##
23
+ # Creates a new AuthenticationError.
24
+ #
25
+ # @param message [String] The error message.
26
+ # @param fault_code [String, nil] The SOAP fault code.
27
+ # @param fault_string [String, nil] The SOAP fault message.
11
28
  def initialize(message, fault_code: nil, fault_string: nil)
12
29
  @fault_code = fault_code
13
30
  @fault_string = fault_string
data/lib/wsaa/tra.rb CHANGED
@@ -1,11 +1,27 @@
1
1
  require 'rexml/document'
2
2
 
3
3
  module Wsaa
4
+ ##
5
+ # Builds the Ticket de Requerimiento de Acceso (TRA) XML document.
6
+ #
7
+ # The TRA is the access request ticket required by WSAA for authentication.
8
+ #
9
+ # @attr_reader service [String] The AFIP service name.
10
+ # @attr_reader generation_time [Time] When the TRA was generated.
11
+ # @attr_reader expiration_time [Time] When the TRA expires.
12
+ # @attr_reader unique_id [Integer] Unique identifier for the request.
4
13
  class Tra
5
14
  TIMEZONE_OFFSET = '-03:00'
6
15
 
7
16
  attr_reader :service, :generation_time, :expiration_time, :unique_id
8
17
 
18
+ ##
19
+ # Creates a new TRA.
20
+ #
21
+ # @param service [String] The AFIP service to authenticate for.
22
+ # @param generation_time [Time, nil] Start of validity period. Defaults to today 00:00:00.
23
+ # @param expiration_time [Time, nil] End of validity period. Defaults to today 23:59:59.
24
+ # @param unique_id [Integer, nil] Unique request identifier. Defaults to current timestamp.
9
25
  def initialize(service:, generation_time: nil, expiration_time: nil, unique_id: nil)
10
26
  @service = service
11
27
  @unique_id = unique_id || Time.now.to_i
@@ -13,6 +29,10 @@ module Wsaa
13
29
  @expiration_time = expiration_time || default_expiration_time
14
30
  end
15
31
 
32
+ ##
33
+ # Converts the TRA to an XML string.
34
+ #
35
+ # @return [String] The TRA as XML.
16
36
  def to_xml
17
37
  doc = REXML::Document.new
18
38
  doc << REXML::XMLDecl.new('1.0', 'UTF-8')
data/lib/wsaa/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module Wsaa
2
- VERSION = '0.1.0'
2
+ ##
3
+ # Current version of the wsaa-ruby gem.
4
+ VERSION = '0.2.1'
3
5
  end
data/lib/wsaa.rb CHANGED
@@ -7,24 +7,68 @@ require_relative 'wsaa/credentials'
7
7
  require_relative 'wsaa/credential_store'
8
8
  require_relative 'wsaa/client'
9
9
 
10
+ ##
11
+ # Main module for WSAA authentication.
12
+ #
13
+ # Provides a simple interface to authenticate with AFIP's WSAA service.
14
+ #
15
+ # @example Configure and authenticate
16
+ # Wsaa.configure do |config|
17
+ # config.pkey = 'path/to/private_key'
18
+ # config.cert = 'path/to/certificate'
19
+ # config.service = 'wsfe'
20
+ # config.environment = :testing
21
+ # end
22
+ #
23
+ # credentials = Wsaa.authenticate
24
+ # credentials.token # => "PD94bWwg..."
25
+ # credentials.sign # => "GGG2XMe..."
10
26
  module Wsaa
11
27
  class << self
28
+ ##
29
+ # Configures the WSAA client.
30
+ #
31
+ # @yield [Configuration] The configuration object.
32
+ #
33
+ # @example
34
+ # Wsaa.configure do |config|
35
+ # config.pkey = 'path/to/key'
36
+ # config.cert = 'path/to/cert'
37
+ # end
12
38
  def configure
13
39
  yield(configuration)
14
40
  end
15
41
 
42
+ ##
43
+ # Returns the current configuration.
44
+ #
45
+ # @return [Configuration] The configuration object.
16
46
  def configuration
17
47
  @configuration ||= Configuration.new
18
48
  end
19
49
 
50
+ ##
51
+ # Authenticates with WSAA using cached credentials if available.
52
+ #
53
+ # @return [Credentials] The authentication credentials.
54
+ # @raise [ConfigurationError] If the configuration is invalid.
55
+ # @raise [AuthenticationError] If authentication fails.
20
56
  def authenticate
21
57
  client.authenticate
22
58
  end
23
59
 
60
+ ##
61
+ # Authenticates with WSAA, ignoring any cached credentials.
62
+ #
63
+ # @return [Credentials] The authentication credentials.
64
+ # @raise [ConfigurationError] If the configuration is invalid.
65
+ # @raise [AuthenticationError] If authentication fails.
24
66
  def authenticate!
25
67
  client.authenticate!
26
68
  end
27
69
 
70
+ ##
71
+ # Resets the configuration and client state.
28
72
  def reset!
29
73
  @configuration = nil
30
74
  @client = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wsaa-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Marcucci
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '6.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '6.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
69
97
  description: Ruby implementation of AFIP WSAA (Web Service de Autenticación y Autorización)
70
98
  for authenticating with Argentine tax authority web services
71
99
  email:
@@ -74,7 +102,9 @@ executables: []
74
102
  extensions: []
75
103
  extra_rdoc_files: []
76
104
  files:
105
+ - AGENTS.md
77
106
  - CHANGELOG.md
107
+ - CLAUDE.md
78
108
  - Gemfile
79
109
  - LICENSE
80
110
  - README.md
@@ -110,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
140
  - !ruby/object:Gem::Version
111
141
  version: '0'
112
142
  requirements: []
113
- rubygems_version: 3.1.6
143
+ rubygems_version: 3.4.19
114
144
  signing_key:
115
145
  specification_version: 4
116
146
  summary: Ruby client for AFIP WSAA authentication service