Commit ab9a80c
feat(hooks): CI annotations and SARIF upload for scanner findings (#2631)
* feat(hooks): surface scanner findings in CI job summary + fix Checkov in Docker image
Security scanner hooks (Checkov, Trivy, KICS, Infracost) already render a
markdown findings summary to the terminal, but it never reached the CI
pipeline — findings were buried in the `atmos terraform plan` log stream.
Route that summary to the GitHub Actions job step summary automatically when
running in GitHub Actions ($GITHUB_STEP_SUMMARY), reusing the existing CI
provider OutputWriter seam:
- pkg/ci/summary.go: new ci.WriteStepSummary helper (no-op outside CI / when
no summary destination), hiding the internal provider OutputWriter type.
- pkg/hooks/command_engine.go: renderCISummary, called after renderTerminal in
CommandEngine.Run. Best-effort — a step-summary write failure logs at debug
and never fails the hook. Covers all four CommandEngine-based scanner/cost
kinds uniformly.
Also fix Checkov crashing inside the official Atmos Docker image: bump the base
image from debian:bookworm-slim (glibc 2.36) to debian:trixie-slim (glibc 2.41)
so the PyInstaller-bundled Checkov binary (needs GLIBC_2.38+) loads its frozen
Python runtime instead of failing with a missing-version error.
Includes unit + end-to-end tests, hooks docs, changelog blog post, and roadmap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): link scanner CI-summary milestone to PR #2617
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): classify Infracost as a cost tool, not a security scanner
Addresses CodeRabbit review on PR #2617: the milestone description grouped
Infracost under "security scanner hooks"; Infracost is a cost-analysis tool.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(hooks): native CI annotations + SARIF Code Scanning upload for scanner findings
Surface scanner-hook findings (checkov/trivy/kics) in CI beyond the job
summary — as inline GitHub annotations on the PR diff and as uploaded SARIF
in GitHub Code Scanning (the Security tab) — natively, without the
github/codeql-action.
CI reporting is modeled as provider capabilities, not hooks (the deprecated
ci.* hook kinds are not revived):
- pkg/ci/internal/provider: new optional capability interfaces Annotator and
SARIFReporter + neutral Annotation/SARIFReport types (opt-in via type
assertion, like CacheProvider/DebugModeDetector).
- pkg/ci/results.go: ci.Annotate / ci.ReportSARIF helpers (Detect →
type-assert → call; no-op otherwise) + public type aliases, mirroring
ci.WriteStepSummary.
- pkg/ci/providers/github: implement Annotate (::error/::warning workflow
commands with proper escaping; severity → level) and ReportSARIF
(CodeScanning.UploadSarif; gzip+base64; category stamped into
runs[].automationDetails.id so per-component uploads don't overwrite).
- pkg/schema: new ci.annotations (default on) and ci.results (default off)
feature gates, siblings of ci.summary/checks/comments; all require ci.enabled.
The hook hands findings to the provider when the gate is on:
- pkg/hooks/sarif: the shared SARIF handler now surfaces parsed findings +
raw SARIF on the Summary (so checkov/trivy/kics are all covered by one
change), labeling by the SARIF tool name when no kind is set.
- pkg/hooks/command_engine.go: emitCIAnnotations + publishCIResults after
renderCISummary; auto-derive the Code Scanning category from the scan
target (component vs stack/component). Reconcile the step-summary to the
ci.enabled gate (was provider-detection-only).
- Custom hooks: a format-handler registry lets kind: command opt in via
format: sarif (+ optional results path), reusing the shared SARIF handler
for any SARIF-emitting tool with no Go code.
Includes unit + end-to-end tests, hooks docs (incl. required GitHub Actions
permissions), changelog blog post, and a roadmap milestone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): link scanner CI annotations/results milestone to PR #2631
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(hooks): clarify GitHub Advanced Security is a paid GitHub add-on for ci.results
Code Scanning is free on public repos; private repos need GitHub Advanced
Security, which GitHub licenses as a paid add-on per active committer — Atmos
charges nothing for any CI reporting. Annotations and the summary need no
add-on. Make this explicit in the hooks docs and blog.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: update ci annotations and actions
* test: add native CI e2e fixture
* feat(hooks): surface scanner findings in CI job summary + fix Checkov in Docker image
Security scanner hooks (Checkov, Trivy, KICS, Infracost) already render a
markdown findings summary to the terminal, but it never reached the CI
pipeline — findings were buried in the `atmos terraform plan` log stream.
Route that summary to the GitHub Actions job step summary automatically when
running in GitHub Actions ($GITHUB_STEP_SUMMARY), reusing the existing CI
provider OutputWriter seam:
- pkg/ci/summary.go: new ci.WriteStepSummary helper (no-op outside CI / when
no summary destination), hiding the internal provider OutputWriter type.
- pkg/hooks/command_engine.go: renderCISummary, called after renderTerminal in
CommandEngine.Run. Best-effort — a step-summary write failure logs at debug
and never fails the hook. Covers all four CommandEngine-based scanner/cost
kinds uniformly.
Also fix Checkov crashing inside the official Atmos Docker image: bump the base
image from debian:bookworm-slim (glibc 2.36) to debian:trixie-slim (glibc 2.41)
so the PyInstaller-bundled Checkov binary (needs GLIBC_2.38+) loads its frozen
Python runtime instead of failing with a missing-version error.
Includes unit + end-to-end tests, hooks docs, changelog blog post, and roadmap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): link scanner CI-summary milestone to PR #2617
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): classify Infracost as a cost tool, not a security scanner
Addresses CodeRabbit review on PR #2617: the milestone description grouped
Infracost under "security scanner hooks"; Infracost is a cost-analysis tool.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(hooks): native CI annotations + SARIF Code Scanning upload for scanner findings
Surface scanner-hook findings (checkov/trivy/kics) in CI beyond the job
summary — as inline GitHub annotations on the PR diff and as uploaded SARIF
in GitHub Code Scanning (the Security tab) — natively, without the
github/codeql-action.
CI reporting is modeled as provider capabilities, not hooks (the deprecated
ci.* hook kinds are not revived):
- pkg/ci/internal/provider: new optional capability interfaces Annotator and
SARIFReporter + neutral Annotation/SARIFReport types (opt-in via type
assertion, like CacheProvider/DebugModeDetector).
- pkg/ci/results.go: ci.Annotate / ci.ReportSARIF helpers (Detect →
type-assert → call; no-op otherwise) + public type aliases, mirroring
ci.WriteStepSummary.
- pkg/ci/providers/github: implement Annotate (::error/::warning workflow
commands with proper escaping; severity → level) and ReportSARIF
(CodeScanning.UploadSarif; gzip+base64; category stamped into
runs[].automationDetails.id so per-component uploads don't overwrite).
- pkg/schema: new ci.annotations (default on) and ci.results (default off)
feature gates, siblings of ci.summary/checks/comments; all require ci.enabled.
The hook hands findings to the provider when the gate is on:
- pkg/hooks/sarif: the shared SARIF handler now surfaces parsed findings +
raw SARIF on the Summary (so checkov/trivy/kics are all covered by one
change), labeling by the SARIF tool name when no kind is set.
- pkg/hooks/command_engine.go: emitCIAnnotations + publishCIResults after
renderCISummary; auto-derive the Code Scanning category from the scan
target (component vs stack/component). Reconcile the step-summary to the
ci.enabled gate (was provider-detection-only).
- Custom hooks: a format-handler registry lets kind: command opt in via
format: sarif (+ optional results path), reusing the shared SARIF handler
for any SARIF-emitting tool with no Go code.
Includes unit + end-to-end tests, hooks docs (incl. required GitHub Actions
permissions), changelog blog post, and a roadmap milestone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(roadmap): link scanner CI annotations/results milestone to PR #2631
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(hooks): clarify GitHub Advanced Security is a paid GitHub add-on for ci.results
Code Scanning is free on public repos; private repos need GitHub Advanced
Security, which GitHub licenses as a paid add-on per active committer — Atmos
charges nothing for any CI reporting. Annotations and the summary need no
add-on. Make this explicit in the hooks docs and blog.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: update ci annotations and actions
* test: add native CI e2e fixture
* Normalize AWS auth endpoint config
* Fix screengrab build command list
* Fix CI annotations and validation failures
* Update quick-start acceptance snapshots
* Normalize SARIF paths for scanner hooks
* Fix native scanner CI annotations
* Scope scanner SARIF category to tool name and event-scoped preflight
Derive the Code Scanning category from the SARIF tool driver name (with
hook kind/command fallback) instead of stack/component, stamp a trailing
slash into automationDetails.id, force non-blocking security-severity on
downgraded findings, and make hook preflight binary checks event-scoped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Scope Native CI to scanner-related path changes
Native CI runs the scanner hooks (checkov/trivy/kics) against the
native-ci-e2e fixture and publishes SARIF + code-scanning annotations.
Running it on every PR spams unrelated PRs with scanner findings. Gate
the pull_request trigger with a paths filter so it only runs when the
fixture, its test-case, the workflow, or the scanner/CI source it
exercises (pkg/ci, pkg/hooks, actions/cache) changes. workflow_dispatch
is unchanged for manual runs. Native CI is not a required check, so
skipping it on unrelated PRs does not block merges.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Reduce native CI scanner findings to one per scanner
The scanner target buckets were completely bare, so trivy (8 findings) and
kics (4 findings) each flagged a dozen-plus distinct S3 misconfigurations,
spamming every PR's code-scanning annotations. Harden each target bucket to
mostly-good defaults with versioning as the single intentional gap, so each
scanner reports exactly one clearly-attributable finding:
- trivy: PAB + CMK encryption + logging -> AWS-0090 (versioning) only
- kics: tags + logging, and exclude the account-level IAM Access Analyzer
query (not a per-bucket property) -> "S3 Bucket Without Versioning" only
- checkov: stays pinned to CKV_AWS_21; its default S3 suite also flags
architectural rules (replication/lifecycle/notifications) out of scope here
Verified locally with trivy 0.70.0 and kics 2.1.20: one finding each.
terraform validate, terraform fmt, and atmos validate stacks all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix doubled SARIF paths for workdir-relative scanner output
kics and Checkov emit SARIF artifactLocation URIs relative to the Atmos
working directory (e.g. components/terraform/<c>/x.tf), which already
include the component prefix. normalizeRel assumed every relative path was
relative to the component dir and prepended sourceRoot, producing doubled
paths (components/terraform/<c>/components/terraform/<c>/x.tf) that GitHub
Code Scanning could not anchor — so only Trivy (which emits an absolute
path) surfaced an annotation on the PR.
Resolve relative paths against candidate bases (repo root, Atmos base
path, scan dir, component dir) and use the first that points at a real
file, so a base already containing the component prefix is not added
twice. Add the Atmos base path as a mapper root and regression tests for
the workdir-relative, file-relative, and absolute cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix native CI apply by keeping scanner targets Floci-applyable
The previous commit hardened the scanner target buckets with KMS keys and
S3 bucket logging to suppress findings via real resources. That broke the
terraform-apply E2E: the Floci emulator cannot create KMS keys
(UnrecognizedClientException) or S3 bucket logging (empty result), so
apply failed even though plan + the scanners passed.
Revert the targets to minimal buckets (apply cleanly on Floci, as the
pre-hardening green runs proved) and control scanner noise in the hooks
instead, so each scanner still reports exactly one finding:
- checkov: --check CKV_AWS_21 (unchanged)
- trivy: --severity MEDIUM (AWS-0090 versioning is the only MEDIUM check)
- kics: --include-queries <versioning> (replaces --exclude-queries)
Verified locally with trivy 0.70.0 and kics 2.1.20: one finding each.
terraform validate/fmt and atmos validate stacks pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Exclude no-color.org from link check (CI timeouts)
The Check Markdown Links job failed with exit code 2 on two TIMEOUT
entries for https://no-color.org/ (referenced from docs/prd/
io-handling-strategy.md and help-system-architecture.md) — 0 real
errors, just a slow external site. Add it to lychee.toml's exclude
list, matching the existing pattern for flaky external domains
(gnu.org, tldp.org, regex101.com, etc.).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Test scanner inline-ignore directives in native CI fixture
Exercise each scanner's native suppression directive end-to-end instead
of only scoping via CLI flags. Each target is scoped to two checks —
versioning + access logging — and the logging finding is suppressed inline
with the scanner's own ignore syntax, proving Atmos runs each scanner in a
context where it can read those directives (without them, two findings
would surface; only versioning should):
- checkov: --check CKV_AWS_21,CKV_AWS_18 + #checkov:skip=CKV_AWS_18
- trivy: --severity MEDIUM,LOW + #trivy:ignore:AWS-0089 (+ public-access
block so the only LOW is logging)
- kics: --include-queries versioning,logging + # kics-scan disable=<logging>
Targets stay Floci-applyable (bucket + public-access block only; no KMS or
S3 logging resources, which Floci cannot create). Verified locally with
checkov 3.3.x, trivy 0.70.0, kics 2.1.20: one finding each. terraform
validate/fmt and atmos validate stacks pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Route KMS to Floci in native CI fixture provider config
Add a kms endpoint to the test stack's AWS provider so aws_kms_key
requests reach the Floci emulator instead of escaping to real AWS (which
fails with UnrecognizedClientException since the test creds are fake).
The current targets don't create KMS keys, but this bakes in the routing
so a future hardened bucket can use customer-managed-key encryption
without rediscovering the missing endpoint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: address code-review findings on scanner CI branch
- native-ci.yml: verify Trivy/KICS binary downloads against their
published sha256 checksums before extraction (supply-chain hardening);
KICS extracted-info.zip has no published checksum and is left as-is.
- hooks.RunAll: add missing perf.Track instrumentation.
- aws endpointURLFromManager: use the actually-matched identity key
(original or lowercase fallback) when resolving the provider config.
- identity_dots test: exercise real key-case preservation with a
mixed-case key and assert IdentityCaseMap retains original casing.
- stores docs: use endpoint: consistently in the Floci example.
- godot: add trailing periods to several comments.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(ci): cover CI-reporting helpers to clear 80% patch gate
Add white-box unit tests for the uncovered/partial branches in the
scanner CI-reporting paths, raising patch coverage on the changed files
from ~82% to ~94% (set-mode) with comfortable margin over Codecov's
partial-counted 80% gate.
- pkg/hooks: emitCIAnnotations, publishCIResults (warn-normalize +
verbatim + no-op branches), reportsAsWarning, firstSARIFToolName,
normalizeSARIFLevels edge/error cases, deriveSARIFCategory fallback,
and the format-handler registry (RegisterFormatHandler /
formatHandlerFor / resolveResultHandler).
- pkg/hooks/sarif: isWindowsDrivePath, cleanAbs, relUnder, fileExists,
relativeBases, normalizeAbs/normalizeRel fallbacks, atmosBasePath,
sourceComponentPath, customFormatOutputPath nil-guard.
- pkg/ci/providers/github: withCategory malformed-run branches,
ReportSARIF missing-context + upload-failure wrapping, Annotate
write-error propagation.
Test-only change; no production code modified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>1 parent c3ab183 commit ab9a80c
102 files changed
Lines changed: 4050 additions & 320 deletions
File tree
- .github
- actions
- go-version-check
- verify-sha-pinning
- workflows
- agent-skills/skills/atmos-auth/references
- cmd
- demo/screengrabs
- docs/fixes
- errors
- examples
- auth-stores
- demo-floci
- quick-start-advanced/stacks/catalog
- vpc-flow-logs-bucket
- vpc
- pkg
- auth
- cloud/aws
- identities/aws
- providers/aws
- ci
- internal/provider
- providers/github
- config
- hooks
- sarif
- schema
- tests
- fixtures/scenarios
- aws-secrets-floci
- aws-store-hooks-floci
- native-ci-e2e
- components/terraform/bucket
- stacks
- catalog
- deploy
- snapshots
- test-cases
- website
- blog
- docs
- cli/configuration
- auth
- stacks
- src/data
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
75 | | - | |
| 75 | + | |
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
273 | 273 | | |
274 | 274 | | |
275 | 275 | | |
276 | | - | |
| 276 | + | |
277 | 277 | | |
278 | 278 | | |
279 | 279 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
| 39 | + | |
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
81 | | - | |
| 81 | + | |
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
86 | | - | |
| 86 | + | |
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
| 97 | + | |
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
77 | | - | |
78 | | - | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
79 | 80 | | |
80 | 81 | | |
81 | 82 | | |
| |||
85 | 86 | | |
86 | 87 | | |
87 | 88 | | |
88 | | - | |
| 89 | + | |
89 | 90 | | |
90 | 91 | | |
91 | 92 | | |
92 | 93 | | |
| 94 | + | |
| 95 | + | |
93 | 96 | | |
94 | 97 | | |
95 | | - | |
| 98 | + | |
96 | 99 | | |
97 | 100 | | |
98 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| |||
0 commit comments