karst 0.1.0 → 0.4.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ARCHITECTURE.md +14 -12
  3. data/CHANGELOG.md +114 -47
  4. data/CONTRIBUTING.md +9 -1
  5. data/README.md +137 -9
  6. data/SECURITY.md +1 -1
  7. data/docs/advanced-configuration.md +112 -7
  8. data/docs/rails8-authentication.md +191 -0
  9. data/docs/request-reproduction.md +242 -0
  10. data/lib/generators/karst/install/templates/karst_initializer.rb +6 -0
  11. data/lib/karst/access/approved_populations.rb +15 -6
  12. data/lib/karst/access/errors.rb +16 -0
  13. data/lib/karst/access/identity_probe.rb +151 -0
  14. data/lib/karst/access/local_path.rb +42 -0
  15. data/lib/karst/access/observed_endpoint.rb +46 -0
  16. data/lib/karst/access/outcome_groups.rb +93 -0
  17. data/lib/karst/access/population_approval.rb +67 -0
  18. data/lib/karst/access/population_discovery.rb +25 -1
  19. data/lib/karst/access/population_revocation.rb +34 -0
  20. data/lib/karst/access/principal_source.rb +24 -3
  21. data/lib/karst/access/probe.rb +397 -0
  22. data/lib/karst/access/search.rb +14 -6
  23. data/lib/karst/access/sweep.rb +42 -112
  24. data/lib/karst/cli/identity_serialization.rb +82 -0
  25. data/lib/karst/cli/outcome_summary.rb +131 -0
  26. data/lib/karst/cli/principal_reference.rb +51 -0
  27. data/lib/karst/cli/reproduction.rb +267 -0
  28. data/lib/karst/cli/verification.rb +219 -55
  29. data/lib/karst/configuration.rb +57 -11
  30. data/lib/karst/execution_context.rb +6 -7
  31. data/lib/karst/identity/evidence.rb +110 -0
  32. data/lib/karst/identity/observation.rb +167 -0
  33. data/lib/karst/identity/warden_adapter.rb +26 -1
  34. data/lib/karst/identity.rb +157 -22
  35. data/lib/karst/mcp/compatibility.rb +24 -0
  36. data/lib/karst/mcp/reproduce_request_tool.rb +137 -0
  37. data/lib/karst/mcp/reproduction.rb +58 -0
  38. data/lib/karst/mcp/server.rb +27 -8
  39. data/lib/karst/mcp/verify_access_tool.rb +36 -2
  40. data/lib/karst/railtie.rb +4 -7
  41. data/lib/karst/reproduction/curl.rb +73 -0
  42. data/lib/karst/reproduction/exercise.rb +246 -0
  43. data/lib/karst/reproduction/observation.rb +87 -0
  44. data/lib/karst/reproduction/sanitizer.rb +210 -0
  45. data/lib/karst/version.rb +1 -1
  46. data/lib/karst/web/badge.rb +5 -31
  47. data/lib/karst/web/browser_identity.rb +10 -13
  48. data/lib/karst/web/csrf.rb +43 -0
  49. data/lib/karst/web/middleware.rb +145 -84
  50. data/lib/karst/web/panel.rb +343 -125
  51. data/lib/karst/web/populations_panel.rb +46 -336
  52. data/lib/karst.rb +3 -3
  53. data/lib/rails/commands/karst/mcp/mcp_command.rb +41 -1
  54. data/lib/rails/commands/karst/reproduce/reproduce_command.rb +67 -0
  55. data/lib/rails/commands/karst/verify/verify_command.rb +14 -2
  56. metadata +38 -18
  57. data/lib/karst/access/population_config_snippet.rb +0 -67
  58. data/lib/karst/access/population_preview.rb +0 -83
  59. data/lib/karst/access/resource_evidence.rb +0 -233
  60. data/lib/karst/spec/catalog.rb +0 -199
  61. data/lib/karst/spec/example_observation.rb +0 -31
  62. data/lib/karst/spec/observer.rb +0 -300
  63. data/lib/karst/spec/principal.rb +0 -12
  64. data/lib/karst/spec/reporter.rb +0 -83
  65. data/lib/karst/spec/request_observation.rb +0 -38
  66. data/lib/karst/spec/scenario.rb +0 -65
  67. data/lib/tasks/karst.rake +0 -34
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../value"
4
-
5
- module Karst
6
- module Spec
7
- # One RSpec example exercising one specific browser-facing controller/action
8
- # request, built entirely from evidence already present in the JSON artifact
9
- # Karst::Spec::Observer writes.
10
- #
11
- # `observed_status`/`observed_redirect` describe what this spec execution
12
- # observed while it ran, never what the example asserted -- a failing or
13
- # pending example still produces a Scenario, and `example_outcome` is how
14
- # a consumer tells "verified" apart from "merely observed."
15
- #
16
- # An example that issues several browser-facing requests (a denied attempt
17
- # followed by an allowed retry, a sign-in followed by the page it unlocks)
18
- # legitimately produces one Scenario per such request: Karst never
19
- # collapses an example down to "its last request," and never labels any
20
- # request as authentication setup versus the subject under test.
21
- #
22
- # `principal_before`/`principal_after` are both kept, not collapsed to
23
- # whichever was active when the request began: a signup or checkout
24
- # scenario that establishes a session is exactly the case where the
25
- # identity a request produces matters as much as the identity it started
26
- # with, and either side alone would discard real evidence.
27
- Scenario = Value.define(
28
- :example_id,
29
- :file_path,
30
- :line_number,
31
- :description_parts,
32
- :full_description,
33
- :karst_explicit,
34
- :karst_name,
35
- :example_outcome,
36
- :controller,
37
- :action,
38
- :http_method,
39
- :route_pattern,
40
- :observed_path,
41
- :observed_status,
42
- :observed_redirect,
43
- :principal_before,
44
- :principal_after,
45
- :principal_changed,
46
- :sequence
47
- ) do
48
- # The most specific zero-config name available without repeating the
49
- # whole describe chain: RSpec's own nesting already puts the most
50
- # specific description last. Never invents a persona the spec itself
51
- # did not name.
52
- def name
53
- karst_name || description_parts.last || full_description
54
- end
55
-
56
- def passed?
57
- example_outcome == :passed
58
- end
59
-
60
- def explicit?
61
- karst_explicit
62
- end
63
- end
64
- end
65
- end
data/lib/tasks/karst.rake DELETED
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :karst do
4
- desc "List zero-argument scopes declared directly in application model source. Never executes them."
5
- task populations: :environment do
6
- require "karst/access/population_discovery"
7
- require "karst/access/population_approvals"
8
-
9
- result = Karst::Access::PopulationDiscovery.new.call
10
- approvals = Karst::Access::PopulationApprovals.load
11
- groups = result.model_groups.reject { |group| group.candidate_names.empty? }
12
-
13
- puts "Warning: #{result.load_warning}\n\n" if result.load_warning
14
- puts "Warning: #{approvals.error}\n\n" if approvals.error
15
- puts "No candidate scopes were discovered." if groups.empty?
16
-
17
- groups.each do |group|
18
- label = group.principal_source ? " (principal source: #{group.principal_source})" : ""
19
- puts "#{group.model_name}#{label} -- #{group.candidate_names.size} scope(s)"
20
- group.candidate_names.each do |name|
21
- puts " #{name}#{' [approved]' if approvals.approved?(group.model_name, name)}"
22
- end
23
- end
24
-
25
- puts "", <<~NOTES
26
- These are discovered scopes only -- Karst has not verified any of them return a usable relation,
27
- and none of this grants access or is wired into sampling on its own.
28
- Only scopes declared directly on application models are included; concern-defined scopes may not appear.
29
- Approve the ones Karst may try at /karst/populations. Approvals are stored locally in
30
- #{Karst::Access::PopulationApprovals.display_path}; delete that file to reset them.
31
- config.principal_populations remains supported and always takes precedence.
32
- NOTES
33
- end
34
- end