From d888b9afc5272452132748c8848ff01d3b9fc23b Mon Sep 17 00:00:00 2001 From: bodaay Date: Mon, 5 Oct 2026 13:13:53 +0300 Subject: [PATCH] Remove Dependabot; monthly manual maintenance; x/crypto 0.57.0; v2.3.0 notes - Delete .github/dependabot.yml. Dependencies are now reviewed once a month by a maintainer, following the new docs/MAINTENANCE.md (exact commands for the Go toolchain, Go/JS/Python/.NET deps, pinned Actions, tests, release). govulncheck still runs on every push/PR and weekly. - golang.org/x/crypto 0.54.0 -> 0.57.0 (supersedes Dependabot #65), with x/net 0.58.0, x/sync 0.23.0, x/sys 0.48.0, x/text 0.42.0. - CHANGELOG v2.3.0: admin console rework, Go 1.26 upgrade note, dependency and CI changes, Dependabot removal. Co-Authored-By: Claude Opus 5.5 --- .github/dependabot.yml | 51 ----------- CHANGELOG.md | 21 ++++- README.md | 1 + docs/MAINTENANCE.md | 190 +++++++++++++++++++++++++++++++++++++++++ go.mod | 10 +-- go.sum | 20 ++--- 6 files changed, 226 insertions(+), 67 deletions(-) delete mode 100644 .github/dependabot.yml create mode 100644 docs/MAINTENANCE.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 36ec529..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,51 +0,0 @@ -# ============================================================================= -# SimpleAuth — Dependabot: automated dependency + Action updates -# ============================================================================= -# Keeps the server, all four SDKs, and the GitHub Actions themselves patched. -# Security updates matter most here — this is an auth server. -# ============================================================================= - -version: 2 -updates: - # Server Go module - - package-ecosystem: gomod - directory: "/" - schedule: - interval: weekly - open-pull-requests-limit: 10 - labels: ["dependencies", "go"] - - # Go SDK module - - package-ecosystem: gomod - directory: "/sdk/go" - schedule: - interval: weekly - labels: ["dependencies", "sdk", "go"] - - # GitHub Actions - - package-ecosystem: github-actions - directory: "/" - schedule: - interval: weekly - labels: ["dependencies", "ci"] - - # JavaScript/TypeScript SDK - - package-ecosystem: npm - directory: "/sdk/js" - schedule: - interval: weekly - labels: ["dependencies", "sdk", "javascript"] - - # Python SDK - - package-ecosystem: pip - directory: "/sdk/python" - schedule: - interval: weekly - labels: ["dependencies", "sdk", "python"] - - # .NET SDK - - package-ecosystem: nuget - directory: "/sdk/dotnet" - schedule: - interval: weekly - labels: ["dependencies", "sdk", "dotnet"] diff --git a/CHANGELOG.md b/CHANGELOG.md index f1db08e..41a90bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,8 @@ Read before upgrading. No configuration is required; the defaults are safe. 3. **AD outage default is `grace` (10 hours).** Previously an AD outage had no effect on already-signed-in users. Now a user not confirmed active in AD within the last 10 hours is denied until AD is reachable again. Right after upgrading, nobody has been confirmed yet: the first successful login, refresh, or SSO after the upgrade records it. If AD goes down before that, those users are denied. Set the policy to `allow` temporarily if you expect AD maintenance right after upgrading. 4. **One extra LDAP search per token refresh and per SSO-cookie reuse** for AD users (about 4 per hour per active session with the default 15-minute access token). 5. **`/api/auth/refresh` now stamps the app's *current* audience** (`aud`) instead of the audience of the original login. If you changed an app's audience, existing sessions switch to the new value at their next refresh. ([SECURITY-AUDIT.md](https://github.com/bodaay/SimpleAuth/blob/master/SECURITY-AUDIT.md) **M40**) -6. **Refresh responses can now be `403 {"error":"account disabled"}`** (`/api/auth/refresh`) or `401 {"error":"invalid_grant","error_description":"account disabled"}` (OIDC) for AD users. Apps must treat these like an expired session and send the user back to login. +6. **Building from source now requires Go 1.26** (`go.mod` is `go 1.26.8`; the Docker image builds with `golang:1.26-alpine`). Prebuilt binaries and the Docker image are unaffected. +7. **Refresh responses can now be `403 {"error":"account disabled"}`** (`/api/auth/refresh`) or `401 {"error":"invalid_grant","error_description":"account disabled"}` (OIDC) for AD users. Apps must treat these like an expired session and send the user back to login. ### Security fixes @@ -51,6 +52,24 @@ Read before upgrading. No configuration is required; the defaults are safe. - **L23 (LOW)**: after the SSO cookie moved from path `/` to the base path, an old `/` cookie survived logout and could silently sign the user back in. Logout now clears both. - **L24 (LOW)**: creating an app-local user (`POST /api/app/users`) ignored store errors and could crash mid-way, leaving a user with no username mapping or roles. It now fails cleanly and rolls back. +### Admin console + +- **Reworked admin UI.** Pages now have their own URLs (`#/users`, `#/apps`, …), so refresh, deep links, and Back/Forward work. The sidebar is grouped into Access / Directory / System. +- **Structured per-app authorization editor**, replacing the raw JSON textarea. Assignments can only use defined roles. +- **Accessible dialogs**: Escape closes them, focus is trapped and restored. Rotating a secret, deleting an app, and enabling require-assignment now ask for confirmation with a warning. +- **Users page**: Edit Profile and Unlock actions, and a "Locked" badge. +- If the admin session expires, the console now returns to the sign-in screen instead of showing a stream of errors. +- New **AD Outage Behavior** card on the Settings page (see the highlight above). + +### Changed + +- **Go 1.26.8** (was 1.25.12). The Go 1.25.12 standard library had 6 vulnerabilities the code reaches (net/url, html/template, crypto/tls, net/http, encoding/xml, encoding/asn1), plus GO-2026-5026 in `golang.org/x/net`. All are fixed. +- Dependencies updated: `golang.org/x/crypto` 0.57.0, `golang.org/x/net` 0.58.0, `github.com/go-ldap/ldap/v3` 3.4.14, `go.etcd.io/bbolt` 1.5.0, `github.com/jackc/pgx/v5` 5.11.0. +- SDK dev dependencies updated: TypeScript 7, `@types/node` 26, and newer Python minimums for `cryptography`, `fastapi`, `starlette`, `django`, and `setuptools`. +- GitHub Actions updated: `actions/checkout` v7, `actions/setup-go` v7, `github/codeql-action` v4.38.2, `softprops/action-gh-release` v3.0.3. +- **Security scan fixed.** The `govulncheck` CI job had been failing to install since `govulncheck` v1.8.0 started requiring a newer Go version, so no scan was actually running. It is now pinned to a working version. +- **Dependabot removed.** Dependencies are now reviewed by a maintainer once a month, following [docs/MAINTENANCE.md](https://github.com/bodaay/SimpleAuth/blob/master/docs/MAINTENANCE.md). `govulncheck` still runs on every push and pull request, and weekly. + ### Added - Runtime settings `directory_outage_policy` (`grace` | `block` | `allow`) and `directory_outage_grace_hours` (1–168, default 10), in `GET/PUT /api/admin/settings` and the admin UI. diff --git a/README.md b/README.md index 484051f..158c3df 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,7 @@ Your app and its auth server, one process, one deploy. See [docs/ARCHITECTURE.md | [SDK Guide](docs/SDK-GUIDE.md) | Client SDK usage | | [Security Audit Log](SECURITY-AUDIT.md) | Every review, finding, and fix | | [Changelog](CHANGELOG.md) | What changed in each release, upgrade notes | +| [Maintenance](docs/MAINTENANCE.md) | Monthly dependency + toolchain checklist (no bots) | ## License diff --git a/docs/MAINTENANCE.md b/docs/MAINTENANCE.md new file mode 100644 index 0000000..5ae2ef5 --- /dev/null +++ b/docs/MAINTENANCE.md @@ -0,0 +1,190 @@ +# Monthly Maintenance Checklist + +SimpleAuth does **not** use Dependabot or any other update bot. Dependencies are reviewed and updated by a maintainer **once a month**, using this checklist. Do the steps in order. Every command is run from the repository root unless a step says otherwise. + +**What you need:** Go (the version in `go.mod`), Node.js 20+, Python 3.11+, Docker, the GitHub CLI (`gh`, logged in), and optionally the .NET 8 SDK. + +The `govulncheck` job in CI (`.github/workflows/security.yml`) still runs on every push and pull request and **every Monday at 06:00 UTC**. It fails the build if the Go code reaches a known vulnerability, so an urgent Go security fix will show up there between monthly checks. + +--- + +## 1. Start from an up-to-date `master` on a new branch + +```bash +git checkout master +git pull --ff-only +git checkout -b chore/monthly-maintenance-$(date +%Y-%m) +``` + +## 2. Go toolchain + +The Go version appears in **three places**, and they must always move together: + +| File | What to change | Example | +|---|---|---| +| `go.mod` | the `go` line | `go 1.26.8` | +| `Dockerfile` | the builder image | `FROM golang:1.26-alpine AS builder` | +| `.github/workflows/security.yml` | the `govulncheck` version, if a newer one supports your Go version | `go install golang.org/x/vuln/cmd/govulncheck@v1.8.0` | + +1. Find the newest **patch** release of your current Go minor version (always use the latest patch — `.0` releases usually have known vulnerabilities): + + ```bash + curl -s 'https://go.dev/dl/?mode=json' | python3 -c "import json,sys; print([r['version'] for r in json.load(sys.stdin)])" + ``` + +2. Set it in `go.mod` (replace `1.26.8` with the version you found): + + ```bash + go mod edit -go=1.26.8 + ``` + +3. Moving to a new **minor** version (e.g. 1.26 → 1.27) is a bigger change: also update the `Dockerfile` builder tag, and add an upgrade note to `CHANGELOG.md` ("building from source now requires Go 1.27"). + +4. Check whether a newer `govulncheck` exists and which Go version it needs: + + ```bash + curl -s https://proxy.golang.org/golang.org/x/vuln/@latest + curl -s https://proxy.golang.org/golang.org/x/vuln/@v/.mod | grep '^go ' + ``` + + Only move the pin in `security.yml` if that `go` line is **not newer** than the one in `go.mod`. + +## 3. Go server dependencies + +```bash +go list -m -u all | grep '\[' # lists modules that have a newer version in [brackets] +go get -u ./... # update direct + indirect deps to the latest minor/patch +go mod tidy +git diff go.mod # review every version change +``` + +- If `go get` changes the `go` line in `go.mod`, a dependency now needs a newer Go. Do step 2 for that version instead of accepting whatever `.0` it picked. +- Do not take a new **major** version (a `/v2`, `/v3` … import path) without reading its release notes. + +Run the vulnerability scanner (use the same version as `security.yml`): + +```bash +go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./... +``` + +Exit code `0` means no reachable vulnerabilities. Anything else: update the module named in the output (or Go itself, if it says "Standard library"). + +## 4. Go SDK (`sdk/go`) + +```bash +cd sdk/go +go list -m -u all | grep '\[' +go get -u ./... && go mod tidy +go build ./... && go vet ./... +cd ../.. +``` + +## 5. JavaScript / TypeScript SDK (`sdk/js`) + +```bash +cd sdk/js +npm outdated # shows current vs latest for typescript and @types/node +npm install --save-dev typescript@latest @types/node@latest +npm run typecheck # must pass +cd ../.. +``` + +## 6. Python SDK (`sdk/python`) + +The minimum versions live in `sdk/python/pyproject.toml`: `dependencies` (`requests`, `cryptography`), `[project.optional-dependencies]` (`fastapi`, `starlette`, `flask`, `django`), and `[build-system] requires` (`setuptools`). For each package, check the latest release: + +```bash +python3 -m pip index versions requests +python3 -m pip index versions cryptography +# …repeat for fastapi, starlette, flask, django, setuptools +``` + +Raise a `>=` lower bound only when the newer version fixes a security issue or is needed. Then confirm the package still installs and imports: + +```bash +python3 -m venv /tmp/sa-venv && /tmp/sa-venv/bin/pip install ./sdk/python \ + && /tmp/sa-venv/bin/python -c "import simpleauth; print('ok')" +``` + +## 7. .NET SDK (`sdk/dotnet`) + +The .NET SDK currently has no NuGet package references. Only check that it still builds (needs the .NET 8 SDK; CI also does this): + +```bash +dotnet build sdk/dotnet/SimpleAuth.csproj -c Release +``` + +## 8. GitHub Actions + +Every action in `.github/workflows/*.yml` is pinned to a **full commit SHA** with the version in a comment, e.g.: + +```yaml +uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 +``` + +1. List what is in use: + + ```bash + grep -rhoE 'uses: [^ ]+@[^ ]+ # [^ ]+' .github/workflows | sort -u + ``` + +2. For each action, find the latest release tag (replace `actions/checkout`): + + ```bash + gh release view --repo actions/checkout --json tagName -q .tagName + ``` + + For `github/codeql-action`, `gh release view` returns a `codeql-bundle-…` tag, which is **not** the action version. Use this instead: + + ```bash + gh api 'repos/github/codeql-action/tags?per_page=100' --jq '.[].name' | grep -E '^v4\.[0-9]+\.[0-9]+$' | sort -V | tail -1 + ``` + +3. Get the commit SHA for that tag and replace **both** the SHA and the `# vX.Y.Z` comment on every line that uses the action: + + ```bash + gh api repos/actions/checkout/commits/v7.0.1 --jq .sha + ``` + + `github/codeql-action/init`, `/autobuild`, and `/analyze` must always use the **same** SHA. + +## 9. Test everything + +All of these must pass before you open the pull request: + +```bash +go vet ./... +go test -race -count=1 ./... +make -C test/integration test # full Docker integration suite (real LDAP, central + standalone); tears itself down +go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./... +(cd sdk/go && go build ./... && go vet ./...) +(cd sdk/js && npm install && npm run typecheck) +docker build -t simpleauth:maintenance-check . +``` + +The integration suite is **not** run by CI, so running it here is the only place it runs. + +## 10. Open the pull request + +```bash +git add -A +git commit -m "chore: monthly maintenance $(date +%Y-%m)" +git push -u origin HEAD +gh pr create --base master --title "chore: monthly maintenance $(date +%Y-%m)" \ + --body "Monthly dependency + toolchain update. All steps of docs/MAINTENANCE.md done; tests pass." +``` + +Merge after CI is green. In `CHANGELOG.md`, add a line under the next version's `### Changed` (or `### Security`, if you fixed a vulnerability) listing what was updated. + +## 11. Releasing (only when you want a new version) + +1. Make sure `CHANGELOG.md` has a section `## vX.Y.Z` for the new version. The release workflow publishes that section as the top of the GitHub Release notes, so write it for operators: highlights, upgrade notes, security fixes. +2. Set the same version in the `VERSION` file (no `v`, e.g. `2.3.0`), commit, and merge to `master`. +3. Tag and push the tag from an up-to-date `master`: + + ```bash + git checkout master && git pull --ff-only + make tag # creates and pushes tag v$(cat VERSION) + ``` + +4. Watch the release run: `gh run watch` (or the repository's **Actions** tab). It builds the binaries and Docker image and creates the GitHub Release. diff --git a/go.mod b/go.mod index 320adfe..69451e8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/jackc/pgx/v5 v5.11.0 github.com/jcmturner/gokrb5/v8 v8.4.4 go.etcd.io/bbolt v1.5.0 - golang.org/x/crypto v0.54.0 + golang.org/x/crypto v0.57.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -27,8 +27,8 @@ require ( github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/kr/text v0.2.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - golang.org/x/net v0.57.0 // indirect - golang.org/x/sync v0.22.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/text v0.40.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sync v0.23.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect ) diff --git a/go.sum b/go.sum index 896c978..6c4c227 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -75,20 +75,20 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -96,8 +96,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=