ace-git-github 0.4.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/lib/ace/git/github/provider.rb +48 -4
- data/lib/ace/git/github/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7712428a17c056a1d6ae36c9bad2c4ef2d90d083b03eed913ea16d83d9b99c6d
|
|
4
|
+
data.tar.gz: 76aa065c65412840d64a1cc3fc75c8c7b1e0649a7c9bcce8947b477a3e476c7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 702969a6a3841f315d52008046ce20323e18667ff035750be93f7305e5187ef529e879ec635daec64957a82b4b6d7a53ed7ce6b1bb7610f23b583d21af2439d3
|
|
7
|
+
data.tar.gz: 17331c5365f2fb16ec22464903c4342ad7e66a7d0342003844aca46c0b11c7826cd59a793a6351a945a35772489ee8a3481745cbff9014ee6a52171bae23cfe2
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-10-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Formal reviewer-owned, exact-head provider approval and read-only approval verification through the forge-neutral review flow; comments do not substitute for approval.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Prove PAT/App user/App installation actors through authenticated GraphQL viewer instead of REST /user; classify unverifiable viewers and integration access refusals truthfully before approval.
|
|
20
|
+
|
|
10
21
|
## [0.4.0] - 2026-10-03
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "digest"
|
|
4
4
|
require "open3"
|
|
5
5
|
require "json"
|
|
6
|
+
require "ace/git/providers/formal_approval"
|
|
6
7
|
require "uri"
|
|
7
8
|
|
|
8
9
|
module Ace
|
|
@@ -510,6 +511,14 @@ end
|
|
|
510
511
|
raise Ace::Git::ProviderMalformedOutputError, "Malformed GitHub repository file content: #{e.message}"
|
|
511
512
|
end
|
|
512
513
|
|
|
514
|
+
def approve_pull_request(number:, expected_head:, body:, correlation:)
|
|
515
|
+
formal_approval.approve(number: number, expected_head: expected_head, body: body, correlation: correlation)
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
def pull_request_approval(number:, expected_head:, review_id:)
|
|
519
|
+
formal_approval.read(number: number, expected_head: expected_head, review_id: review_id)
|
|
520
|
+
end
|
|
521
|
+
|
|
513
522
|
def create_pull_request_comment(number:, expected_head:, body:, correlation:)
|
|
514
523
|
pr = verify_expected_head!(pull_request(number: number), expected_head)
|
|
515
524
|
require_open_pr!(pr)
|
|
@@ -894,6 +903,41 @@ end
|
|
|
894
903
|
)
|
|
895
904
|
end
|
|
896
905
|
|
|
906
|
+
def formal_approval
|
|
907
|
+
request = lambda do |method, path, payload|
|
|
908
|
+
if path == :actor
|
|
909
|
+
formal_review_actor
|
|
910
|
+
else
|
|
911
|
+
gh_api(path, method: method, payload: payload)
|
|
912
|
+
end
|
|
913
|
+
end
|
|
914
|
+
Ace::Git::Providers::FormalApproval.new(provider: self, request: request,
|
|
915
|
+
list: ->(path) { gh_api_pages(path) })
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
# GitHub documents installation-token GraphQL viewer queries. Use the
|
|
919
|
+
# same configured credential for PAT/App user/App installation identities;
|
|
920
|
+
# REST /user is not an installation-token actor endpoint.
|
|
921
|
+
def formal_review_actor
|
|
922
|
+
result = gh_api("graphql", method: :post, global: true,
|
|
923
|
+
payload: {"query" => "query { viewer { login databaseId } }"})
|
|
924
|
+
viewer = result.is_a?(Hash) && result.dig("data", "viewer")
|
|
925
|
+
errors = result.is_a?(Hash) && result["errors"]
|
|
926
|
+
unless (!errors || errors == []) && viewer.is_a?(Hash) &&
|
|
927
|
+
viewer["databaseId"].is_a?(Integer) && viewer["databaseId"].positive? &&
|
|
928
|
+
viewer["login"].is_a?(String) && !viewer["login"].empty?
|
|
929
|
+
raise Ace::Git::ProviderUnsupportedCapabilityError,
|
|
930
|
+
"Configured GitHub credential cannot provide a verified GraphQL viewer actor; no approval performed"
|
|
931
|
+
end
|
|
932
|
+
{"id" => viewer["databaseId"], "login" => viewer["login"]}
|
|
933
|
+
rescue Ace::Git::ProviderAuthenticationError => error
|
|
934
|
+
if error.message.match?(/resource not accessible by integration/i)
|
|
935
|
+
raise Ace::Git::ProviderUnsupportedCapabilityError,
|
|
936
|
+
"Configured GitHub integration credential cannot verify its GraphQL viewer actor; no approval performed"
|
|
937
|
+
end
|
|
938
|
+
raise
|
|
939
|
+
end
|
|
940
|
+
|
|
897
941
|
def gh_api_pages(suffix)
|
|
898
942
|
data = gh_api(suffix, paginate: true)
|
|
899
943
|
pages = data.is_a?(Array) ? data : nil
|
|
@@ -903,13 +947,13 @@ end
|
|
|
903
947
|
pages.flatten(1)
|
|
904
948
|
end
|
|
905
949
|
|
|
906
|
-
def gh_api(suffix, method: :get, body: nil, paginate: false)
|
|
950
|
+
def gh_api(suffix, method: :get, body: nil, paginate: false, payload: nil, global: false)
|
|
907
951
|
target = Ace::Git::Atoms::ServerUrl.normalize(server.url)
|
|
908
952
|
host, repository = target.split("/", 2)
|
|
909
953
|
unless repository&.match?(%r{\A[^/]+/[^/]+\z})
|
|
910
954
|
raise Ace::Git::ConfigError, "Invalid selected GitHub repository #{server.url}"
|
|
911
955
|
end
|
|
912
|
-
args = ["repos/#{repository}/#{suffix}", "--hostname", host]
|
|
956
|
+
args = [global ? suffix : "repos/#{repository}/#{suffix}", "--hostname", host]
|
|
913
957
|
args += ["--paginate", "--slurp"] if paginate
|
|
914
958
|
stdin = nil
|
|
915
959
|
if %i[post patch].include?(method)
|
|
@@ -917,7 +961,7 @@ end
|
|
|
917
961
|
# command argument: argv leaks into process listings and
|
|
918
962
|
# timeout errors, and huge review bodies exceed arg limits.
|
|
919
963
|
args += ["-X", method.to_s.upcase, "--input", "-"]
|
|
920
|
-
stdin = JSON.generate(body: body)
|
|
964
|
+
stdin = JSON.generate(payload || {body: body})
|
|
921
965
|
end
|
|
922
966
|
result = CliExecutor.execute("api", args, timeout: timeout, runner: runner, stdin: stdin)
|
|
923
967
|
classify_failure(result[:stderr], context: "api #{suffix}") unless result[:success]
|
|
@@ -1168,7 +1212,7 @@ end
|
|
|
1168
1212
|
message = stderr.to_s
|
|
1169
1213
|
if message.match?(PrFetcher::PR_NOT_FOUND_PATTERN)
|
|
1170
1214
|
raise Ace::Git::ProviderObjectNotFoundError, "Object not found: #{context}: #{message}"
|
|
1171
|
-
elsif message.match?(PrFetcher::AUTH_ERROR_PATTERN)
|
|
1215
|
+
elsif message.match?(PrFetcher::AUTH_ERROR_PATTERN) || message.match?(/HTTP 40[13]|resource not accessible by integration/i)
|
|
1172
1216
|
raise Ace::Git::ProviderAuthenticationError, "Not authenticated with GitHub: #{message}"
|
|
1173
1217
|
elsif message.match?(/match[- ]head[- ]commit|head commit/i)
|
|
1174
1218
|
raise Ace::Git::ProviderExpectedHeadConflictError,
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-git-github
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-git
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '0.
|
|
18
|
+
version: '0.31'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '0.
|
|
25
|
+
version: '0.31'
|
|
26
26
|
description: 'Implements the shared ace-git provider contract for GitHub: all `gh`
|
|
27
27
|
CLI invocation, output parsing, authentication verification, and classified failure
|
|
28
28
|
handling live behind one normalized evidence boundary.'
|