auditea 0.1.0.beta.5 → 0.1.0.beta.6

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: 8ed0a68e5bfed09c0f764146e65c9b995d11c7070224a19fc6e682367626d0d1
4
- data.tar.gz: cfdc642f25cab8125b3c8479b9aacbbaa13613650fa12a9b8160e21d92c2881f
3
+ metadata.gz: a53fe361e4064b6efcdc0102f09a27a356f76d116b88b531774e93e1ffaafeb6
4
+ data.tar.gz: be811c131585c9ba97cdf4cef22c57309d293af0709b1b65ef756a44602d50e3
5
5
  SHA512:
6
- metadata.gz: 35cd56bc10b1010767e8078d5719639e12a056bc13aacd9472d1cda46d9679ddefba7519988af49faa26f7efd8ee664bdb1fe3f78eb27655b74c391a556406b6
7
- data.tar.gz: 7911d88e0322ceba880eaeb09f0825d74079107612022aa60fbfff1e6e974a43a44b31d386ee304a5ff1d855d17ea1ca657198c4c3637eb7db6700ac2cb03dd6
6
+ metadata.gz: 270fabedbb574108c32286ae01149d38e23ad17c3e28fd65abaf924d77f9244172807225e0e0c013a59551514ff82372ec1134ef75ad02b16c605cd87198e3dd
7
+ data.tar.gz: e42afa22d152260e21f3826075b2b2b1a07a0bedf78541bc320020b439dc23cb601f853e790606f847c124879c9331e1a59ef97e17593a387294cb2d10cc7bce
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0.beta.5 (unreleased)
3
+ ## 0.1.0.beta.6 (unreleased)
4
+
5
+ ### Windows host inventory (additive)
6
+
7
+ - Conservative Windows OS edition detection for host inventory posture (`WindowsOs` consumers on the server)
8
+ - Conservative read-only Windows Apache service discovery (`AUD-SDK-APACHE-SERVICE01`) — service-name observation only; never claims Apache is absent when not observed
9
+ - Windows smoke helpers under `examples/` for controlled field validation (IRCM native smoke deferred to a separate scheduled run)
10
+
11
+ ## 0.1.0.beta.5
4
12
 
5
13
  ### SDK readiness diagnostic
6
14
 
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ruby / Rails SDK for [AudiTea](https://github.com/reznis/AudiTea) event collection.
4
4
 
5
- Version: **0.1.0.beta.5** (proposed, not yet published)
5
+ Version: **0.1.0.beta.6** (published)
6
6
 
7
7
  Captures durable technical and business evidence. AudiTea **server** owns taxonomy, dictionary, human labels, vulnerability matching, correlation, and reinterpretation.
8
8
 
@@ -12,7 +12,7 @@ The SDK does **not** perform vulnerability scanning, OS package/CVE inventory, d
12
12
 
13
13
  ```ruby
14
14
  # Gemfile
15
- gem "auditea", "0.1.0.beta.5"
15
+ gem "auditea", "0.1.0.beta.6"
16
16
  ```
17
17
 
18
18
  ```bash
data/RELEASE.md CHANGED
@@ -1,4 +1,4 @@
1
- # Release: auditea 0.1.0.beta.5
1
+ # Release: auditea 0.1.0.beta.6
2
2
 
3
3
  Authoritative runbook for controlled beta publication of the Ruby SDK.
4
4
 
@@ -169,10 +169,10 @@ PR status may say `READY FOR HUMAN PUBLICATION REVIEW` while still listing exter
169
169
  ```bash
170
170
  git checkout main
171
171
  git pull
172
- # confirm VERSION and CHANGELOG still say 0.1.0.beta.5
172
+ # confirm VERSION and CHANGELOG still say 0.1.0.beta.6
173
173
  gem build auditea.gemspec
174
174
  # inspect package once more
175
- gem push auditea-0.1.0.beta.5.gem
175
+ gem push auditea-0.1.0.beta.6.gem
176
176
  ```
177
177
 
178
178
  Then mark CHANGELOG released with the publication date in a follow-up commit.
@@ -182,9 +182,9 @@ Then mark CHANGELOG released with the publication date in a follow-up commit.
182
182
  ## Post-publication verification
183
183
 
184
184
  ```bash
185
- gem install auditea -v 0.1.0.beta.5 --pre
185
+ gem install auditea -v 0.1.0.beta.6 --pre
186
186
  ruby -rauditea -e 'puts Auditea::VERSION'
187
- # expect: 0.1.0.beta.5
187
+ # expect: 0.1.0.beta.6
188
188
  ```
189
189
 
190
190
  Prefer installing the RubyGems artifact (not a git branch) into the controlled TEST app.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "timeout"
4
4
  require_relative "../inventory/components"
5
+ require_relative "windows_services"
5
6
 
6
7
  module Auditea
7
8
  module HostInventory
@@ -97,7 +98,17 @@ module Auditea
97
98
  )
98
99
  end
99
100
  end
100
- seen.values
101
+
102
+ components = seen.values
103
+ # Service discovery is a fallback for products the uninstall registry
104
+ # misses (manually unpacked ZIP, service-only install). When uninstall
105
+ # already proves an Apache HTTP Server installation (with a version), do
106
+ # not add a version-less service observation for the same installation.
107
+ unless components.any? { |c| c["product"] == "Apache HTTP Server" }
108
+ components += WindowsServices.collect(deadline: deadline)
109
+ end
110
+
111
+ components
101
112
  end
102
113
 
103
114
  def parse_uninstall(output)
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "windows_components"
4
+
5
+ module Auditea
6
+ module HostInventory
7
+ # Conservative read-only Windows service discovery. Proves Apache HTTP
8
+ # Server identity from trusted service metadata WITHOUT executing the
9
+ # binary, trusting caller paths, or inferring a version from a directory
10
+ # name. A proven-but-unversioned service is reported with version nil so
11
+ # the server can show "Not reported" rather than hiding a known install.
12
+ #
13
+ # Reads only HKLM\SYSTEM\CurrentControlSet\Services (a single, non-WOW64-
14
+ # redirected view). Reuses WindowsComponents.run_reg so the read remains
15
+ # bounded, timeout-protected, fail-open, and read-only.
16
+ module WindowsServices
17
+ SERVICES_KEY = 'HKLM\SYSTEM\CurrentControlSet\Services'
18
+ # Explicit generic Windows software channel (same as uninstall detection).
19
+ WINDOWS_PACKAGE = { "ecosystem" => "windows" }.freeze
20
+
21
+ module_function
22
+
23
+ # Single deterministic read-only services query.
24
+ def service_queries
25
+ [["query", SERVICES_KEY, "/s"]]
26
+ end
27
+
28
+ def collect(deadline:)
29
+ components = []
30
+ apache_emitted = false
31
+
32
+ service_queries.each do |argv|
33
+ remaining = deadline - WindowsComponents.monotonic_now
34
+ break if remaining <= 0
35
+
36
+ output = WindowsComponents.run_reg(
37
+ argv,
38
+ timeout: [WindowsComponents::PER_COMMAND_TIMEOUT_SECONDS, remaining].min
39
+ )
40
+ next if output.nil?
41
+
42
+ parse_services(output).each do |(display_name, image_path)|
43
+ next unless apache_http_server_service?(display_name, image_path)
44
+ next if apache_emitted
45
+
46
+ apache_emitted = true
47
+ components << Inventory::Components.build_without_version(
48
+ product: "Apache HTTP Server",
49
+ scope: "reverse_proxy",
50
+ observation_method: "windows.service_registry",
51
+ package: WINDOWS_PACKAGE,
52
+ evidence: { "command" => "reg.exe" }
53
+ )
54
+ end
55
+ end
56
+
57
+ components
58
+ end
59
+
60
+ # Parses `reg query ...\Services /s` output into [display_name, image_path]
61
+ # pairs, one per service subkey. Ignores values we do not need; never
62
+ # returns raw output or paths as evidence.
63
+ def parse_services(output)
64
+ services = []
65
+ display_name = nil
66
+ image_path = nil
67
+ output.to_s.each_line do |line|
68
+ stripped = line.strip
69
+ if stripped.start_with?("HKEY_")
70
+ services << [display_name, image_path] if display_name || image_path
71
+ display_name = nil
72
+ image_path = nil
73
+ next
74
+ end
75
+
76
+ if (match = stripped.match(/\ADisplayName\s+REG_\S+\s+(.+)\z/i))
77
+ display_name = match[1].to_s.strip
78
+ elsif (match = stripped.match(/\AImagePath\s+REG_\S+\s+(.+)\z/i))
79
+ image_path = match[1].to_s.strip
80
+ end
81
+ end
82
+ services << [display_name, image_path] if display_name || image_path
83
+ services
84
+ end
85
+
86
+ # Proves Apache HTTP Server identity from trusted service metadata. An
87
+ # `httpd.exe` ImagePath is the unambiguous Apache HTTP Server binary;
88
+ # a conservative DisplayName match covers the common "Apache2.4" /
89
+ # "Apache HTTP Server" names while rejecting unrelated Apache projects
90
+ # (Tomcat, Cassandra, DS, ...).
91
+ def apache_http_server_service?(display_name, image_path)
92
+ path = image_path.to_s.strip
93
+ return true if path.match?(%r{(?:\A|[\\/])httpd\.exe(?:["'\s]|\z)}i)
94
+
95
+ name = display_name.to_s.strip
96
+ return false if name.empty?
97
+ return false if name.match?(/\btomcat\b/i)
98
+
99
+ name.match?(/\Aapache(?:\s+http\s+server(?:\s+\d+(?:\.\d+)*)?|\s*\d+(?:\.\d+)*)?\s*\z/i)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -41,6 +41,26 @@ module Auditea
41
41
  entry
42
42
  end
43
43
 
44
+ # A component whose identity is proven but whose version is not available
45
+ # (e.g. an Apache HTTP Server proven as a Windows service, where no
46
+ # authoritative version metadata exists). Emits the component WITHOUT a
47
+ # `version` key so the server can truthfully render "Not reported" rather
48
+ # than inventing or silently dropping the known installed product.
49
+ def build_without_version(product:, scope:, observation_method:, package: nil, evidence: nil)
50
+ return nil unless SCOPES.include?(scope.to_s)
51
+ return nil if blank?(product)
52
+
53
+ entry = {
54
+ "product" => truncate(product, MAX_PRODUCT),
55
+ "scope" => scope.to_s,
56
+ "observation_method" => truncate(observation_method, MAX_METHOD)
57
+ }
58
+ entry["package"] = package if package.is_a?(Hash) && !package.empty?
59
+ sanitized = sanitize_evidence(evidence)
60
+ entry["evidence"] = sanitized if sanitized
61
+ entry
62
+ end
63
+
44
64
  def sanitize_evidence(value)
45
65
  return nil unless value.is_a?(Hash)
46
66
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Auditea
4
- VERSION = "0.1.0.beta.5"
4
+ VERSION = "0.1.0.beta.6"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: auditea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta.5
4
+ version: 0.1.0.beta.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - AudiTea
@@ -39,6 +39,7 @@ files:
39
39
  - lib/auditea/host_inventory/component_detectors.rb
40
40
  - lib/auditea/host_inventory/emitter.rb
41
41
  - lib/auditea/host_inventory/windows_components.rb
42
+ - lib/auditea/host_inventory/windows_services.rb
42
43
  - lib/auditea/instrumentation/active_job.rb
43
44
  - lib/auditea/instrumentation/error_subscriber.rb
44
45
  - lib/auditea/instrumentation/exception.rb