Module: Karst::Access
- Defined in:
- lib/karst/access/sweep.rb,
lib/karst/access/search.rb,
lib/karst/access/principal_source.rb,
lib/karst/access/principal_sampler.rb,
lib/karst/access/probe_application.rb,
lib/karst/access/database_isolation.rb,
lib/karst/access/population_approval.rb,
lib/karst/access/principal_selection.rb,
lib/karst/access/approved_populations.rb,
lib/karst/access/candidate_population.rb,
lib/karst/access/population_approvals.rb,
lib/karst/access/population_discovery.rb,
lib/karst/access/population_revocation.rb,
lib/karst/access/sensitive_attribute_names.rb,
lib/karst/access/principal_source_selection.rb,
lib/karst/access/selected_principal_sources.rb
Defined Under Namespace
Modules: ApprovedPopulations, PopulationApprovals, PrincipalSourceSelection, SelectedPrincipalSources, SensitiveAttributeNames Classes: DatabaseIsolation, Error, PopulationApproval, PopulationDiscovery, PopulationRevocation, PrincipalSampler, PrincipalSelection, PrincipalSource, ProbeApplication, Search, Sweep, Unavailable, UnsafeTarget, UnsupportedMethod
Constant Summary collapse
- Outcome =
sampling_reasons is a frozen Array of short evidence strings (e.g. "role=local_admin", "source=authors") explaining why PrincipalSampler or PrincipalSelection deliberately included this principal, or an empty Array when the principal came from plain first-N/fill sampling or was supplied directly rather than through a sampler. This is sampling evidence, not an authorization claim.
Value.define(:principal, :status, :redirect, :exception_class, :writes_observed, :write_count, :elapsed_ms, :database_rollback_attempted, :sampling_reasons, :body_marker_observed, :halted_callback)
- Result =
candidate_pool_size is nil unless the caller supplying
principals(see Access::PrincipalSampler::Result) knows it sampled from a bounded recent-N pool rather than the full principal source -- callers use it to report the sampling scope truthfully rather than implying every principal was considered. Value.define(:path, :http_method, :outcomes, :elapsed_ms, :aborted_reason, :database_isolation, :candidate_pool_size) do def groups outcomes.group_by { |item| [item.status, item.redirect, item.exception_class, item.halted_callback] } end end
- CandidatePopulation =
An application-authored, bounded subset of a model's rows -- for example the rows a configured callable like
-> { User.system_admins }returns. A population is a hint about where meaningful sampling candidates might live; it is never a claim about behavior or authorization -- only Access::Sweep's runtime execution produces that evidence. See README "Candidate populations" for the full boundary this class exists to preserve.Deliberately generic over what a "candidate" represents. Today's only caller (PrincipalSampler) always treats these records as principals, but nothing here assumes that -- a future artifact-population caller (Subscription.renewable, Import.with_sheets) could resolve populations exactly the same way over a non-principal model, without this class changing at all.
This deliberately does not claim that a configured callable is a "real" Rails named scope. Active Record exposes no reliable, public way to distinguish a method defined via the
scopemacro from an ordinary handwritten class method, so Karst only validates the one thing it can actually observe: calling the configured callable returns an ActiveRecord::Relation scoped to the same model being sampled. Whether that relation came fromscope :system_admins, -> { ... }or a plaindef self.system_admins; ...; endmakes no difference here. rubocop:disable Metrics/BlockLength Value.define(:source, :name, :records, :provenance) do class << self # Resolves one configured name => callable pair into a bounded, # already-queried population, or nil when calling the callable does # not yield an ActiveRecord::Relation scoped to source_klass (wrong # type, wrong model, or the callable itself raising -- including # requiring an argument Karst never supplies). Invalid populations # are skipped, never raised: a misconfigured population should # degrade the candidate pool, not break the sweep. Issues at most # one SELECT query, always LIMIT-bounded -- never a COUNT, never full # materialization, regardless of how many rows the underlying # relation matches. Evaluation and materialization happen inside a # rollback-only transaction on the source model's connection. A # candidate that emits mutating SQL is rejected even though Karst # attempted to roll that transaction back. def resolve(name:, callable:, source_klass:, limit:) evaluation = evaluate(callable, source_klass, limit) return nil unless usable_evaluation?(evaluation) records = evaluation.value return nil unless records new(source: source_klass, name: name.to_sym, records: records, provenance: "population=#{name}") rescue StandardError nil end private def evaluate(callable, source_klass, limit) DatabaseIsolation.call(connection_class: source_klass) do relation = callable.call next unless relation.is_a?(ActiveRecord::Relation) && relation.klass == source_klass bounded(relation, source_klass, limit) end end def usable_evaluation?(evaluation) evaluation.exception.nil? && evaluation.write_count.zero? && evaluation.database_rollback_attempted end # Only imposes primary-key ordering as a deterministic fallback when # the configured relation has none of its own -- an application's # own meaningful order (e.g. most-recently-flagged first) is # respected rather than silently overridden. def bounded(relation, klass, limit) ordered = relation.order_values.empty? ? relation.order(klass.primary_key) : relation ordered.limit(limit).to_a end end end