mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
Bumps the github-actions group with 4 updates: [crate-ci/typos](https://github.com/crate-ci/typos), [google-github-actions/auth](https://github.com/google-github-actions/auth), [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud) and [google-github-actions/get-gke-credentials](https://github.com/google-github-actions/get-gke-credentials). Updates `crate-ci/typos` from 1.26.8 to 1.27.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/crate-ci/typos/releases">crate-ci/typos's releases</a>.</em></p> <blockquote> <h2>v1.27.0</h2> <h2>[1.27.0] - 2024-11-01</h2> <h3>Features</h3> <ul> <li>Updated the dictionary with the <a href="https://redirect.github.com/crate-ci/typos/issues/1106">October 2024</a> changes</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's changelog</a>.</em></p> <blockquote> <h1>Change Log</h1> <p>All notable changes to this project will be documented in this file.</p> <p>The format is based on <a href="http://keepachangelog.com/">Keep a Changelog</a> and this project adheres to <a href="http://semver.org/">Semantic Versioning</a>.</p> <!-- raw HTML omitted --> <h2>[Unreleased] - ReleaseDate</h2> <h2>[1.27.0] - 2024-11-01</h2> <h3>Features</h3> <ul> <li>Updated the dictionary with the <a href="https://redirect.github.com/crate-ci/typos/issues/1106">October 2024</a> changes</li> </ul> <h2>[1.26.8] - 2024-10-24</h2> <h2>[1.26.7] - 2024-10-24</h2> <h2>[1.26.6] - 2024-10-24</h2> <h2>[1.26.5] - 2024-10-24</h2> <h2>[1.26.4] - 2024-10-24</h2> <h2>[1.26.3] - 2024-10-24</h2> <h3>Fixes</h3> <ul> <li>Accept <code>additionals</code></li> </ul> <h2>[1.26.2] - 2024-10-24</h2> <h3>Fixes</h3> <ul> <li>Accept <code>tesselate</code> variants</li> </ul> <h2>[1.26.1] - 2024-10-23</h2> <h3>Fixes</h3> <ul> <li>Respect <code>--force-exclude</code> for binary files</li> </ul> <h2>[1.26.0] - 2024-10-07</h2> <h3>Compatibility</h3> <ul> <li><em>(pre-commit)</em> Requires 3.2+</li> </ul> <h3>Fixes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="d01f29c66d
"><code>d01f29c</code></a> chore: Release</li> <li><a href="52e950bb13
"><code>52e950b</code></a> chore: Release</li> <li><a href="19cfc03ea4
"><code>19cfc03</code></a> docs: Update changelog</li> <li><a href="f80b1564bd
"><code>f80b156</code></a> Merge pull request <a href="https://redirect.github.com/crate-ci/typos/issues/1140">#1140</a> from epage/oct</li> <li><a href="6b5c8079a9
"><code>6b5c807</code></a> feat(dict): Oct updates</li> <li><a href="d64f202a88
"><code>d64f202</code></a> chore(deps): Update compatible (<a href="https://redirect.github.com/crate-ci/typos/issues/1137">#1137</a>)</li> <li><a href="e903c46287
"><code>e903c46</code></a> Merge pull request <a href="https://redirect.github.com/crate-ci/typos/issues/1136">#1136</a> from PigeonF/PigeonF/push-mlqnlvmswwmp</li> <li><a href="b994765ef9
"><code>b994765</code></a> chore: Fix typo "potemtial" -> "potential"</li> <li>See full diff in <a href="0d9e0c2c1b...d01f29c66d
">compare view</a></li> </ul> </details> <br /> Updates `google-github-actions/auth` from 2.1.6 to 2.1.7 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/google-github-actions/auth/releases">google-github-actions/auth's releases</a>.</em></p> <blockquote> <h2>v2.1.7</h2> <h2>What's Changed</h2> <ul> <li>fix: update relase workflows by <a href="https://github.com/verbanicm"><code>@verbanicm</code></a> in <a href="https://redirect.github.com/google-github-actions/auth/pull/452">google-github-actions/auth#452</a></li> <li>Release: v2.1.7 by <a href="https://github.com/google-github-actions-bot"><code>@google-github-actions-bot</code></a> in <a href="https://redirect.github.com/google-github-actions/auth/pull/453">google-github-actions/auth#453</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/google-github-actions/auth/compare/v2.1.6...v2.1.7">https://github.com/google-github-actions/auth/compare/v2.1.6...v2.1.7</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="6fc4af4b14
"><code>6fc4af4</code></a> Release: v2.1.7 (<a href="https://redirect.github.com/google-github-actions/auth/issues/453">#453</a>)</li> <li><a href="212f83afe8
"><code>212f83a</code></a> fix: update relase workflows (<a href="https://redirect.github.com/google-github-actions/auth/issues/452">#452</a>)</li> <li>See full diff in <a href="8254fb75a3...6fc4af4b14
">compare view</a></li> </ul> </details> <br /> Updates `google-github-actions/setup-gcloud` from 2.1.1 to 2.1.2 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/google-github-actions/setup-gcloud/releases">google-github-actions/setup-gcloud's releases</a>.</em></p> <blockquote> <h2>v2.1.2</h2> <h2>What's Changed</h2> <ul> <li>fix: update release workflows by <a href="https://github.com/verbanicm"><code>@verbanicm</code></a> in <a href="https://redirect.github.com/google-github-actions/setup-gcloud/pull/698">google-github-actions/setup-gcloud#698</a></li> <li>Release: v2.1.2 by <a href="https://github.com/google-github-actions-bot"><code>@google-github-actions-bot</code></a> in <a href="https://redirect.github.com/google-github-actions/setup-gcloud/pull/699">google-github-actions/setup-gcloud#699</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/google-github-actions/setup-gcloud/compare/v2.1.1...v2.1.2">https://github.com/google-github-actions/setup-gcloud/compare/v2.1.1...v2.1.2</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="6189d56e40
"><code>6189d56</code></a> Release: v2.1.2 (<a href="https://redirect.github.com/google-github-actions/setup-gcloud/issues/699">#699</a>)</li> <li><a href="413dc083dd
"><code>413dc08</code></a> fix: update release workflows (<a href="https://redirect.github.com/google-github-actions/setup-gcloud/issues/698">#698</a>)</li> <li>See full diff in <a href="f0990588f1...6189d56e40
">compare view</a></li> </ul> </details> <br /> Updates `google-github-actions/get-gke-credentials` from 2.2.1 to 2.2.2 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/google-github-actions/get-gke-credentials/releases">google-github-actions/get-gke-credentials's releases</a>.</em></p> <blockquote> <h2>v2.2.2</h2> <h2>What's Changed</h2> <ul> <li>Fix package name by <a href="https://github.com/sethvargo"><code>@sethvargo</code></a> in <a href="https://redirect.github.com/google-github-actions/get-gke-credentials/pull/312">google-github-actions/get-gke-credentials#312</a></li> <li>fix: update release workflows by <a href="https://github.com/verbanicm"><code>@verbanicm</code></a> in <a href="https://redirect.github.com/google-github-actions/get-gke-credentials/pull/313">google-github-actions/get-gke-credentials#313</a></li> <li>Release: v2.2.2 by <a href="https://github.com/google-github-actions-bot"><code>@google-github-actions-bot</code></a> in <a href="https://redirect.github.com/google-github-actions/get-gke-credentials/pull/315">google-github-actions/get-gke-credentials#315</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/google-github-actions/get-gke-credentials/compare/v2.2.1...v2.2.2">https://github.com/google-github-actions/get-gke-credentials/compare/v2.2.1...v2.2.2</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="206d64b64b
"><code>206d64b</code></a> Release: v2.2.2 (<a href="https://redirect.github.com/google-github-actions/get-gke-credentials/issues/315">#315</a>)</li> <li><a href="0fead37d80
"><code>0fead37</code></a> fix: update release workflows (<a href="https://redirect.github.com/google-github-actions/get-gke-credentials/issues/313">#313</a>)</li> <li><a href="d7d8311fd5
"><code>d7d8311</code></a> Fix package name (<a href="https://redirect.github.com/google-github-actions/get-gke-credentials/issues/312">#312</a>)</li> <li>See full diff in <a href="6051de21ad...206d64b64b
">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Muhammad Atif Ali <me@matifali.dev>
203 lines
6.1 KiB
Go
203 lines
6.1 KiB
Go
package httpmw
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"database/sql"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/google/uuid"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/coderd/database"
|
|
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
|
"github.com/coder/coder/v2/coderd/httpapi"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
)
|
|
|
|
const (
|
|
// WorkspaceProxyAuthTokenHeader is the auth header used for requests from
|
|
// external workspace proxies.
|
|
//
|
|
// The format of an external proxy token is:
|
|
// <proxy id>:<proxy secret>
|
|
//
|
|
//nolint:gosec
|
|
WorkspaceProxyAuthTokenHeader = "Coder-External-Proxy-Token"
|
|
)
|
|
|
|
type workspaceProxyContextKey struct{}
|
|
|
|
// WorkspaceProxyOptional may return the workspace proxy from the ExtractWorkspaceProxy
|
|
// middleware.
|
|
func WorkspaceProxyOptional(r *http.Request) (database.WorkspaceProxy, bool) {
|
|
proxy, ok := r.Context().Value(workspaceProxyContextKey{}).(database.WorkspaceProxy)
|
|
return proxy, ok
|
|
}
|
|
|
|
// WorkspaceProxy returns the workspace proxy from the ExtractWorkspaceProxy
|
|
// middleware.
|
|
func WorkspaceProxy(r *http.Request) database.WorkspaceProxy {
|
|
proxy, ok := WorkspaceProxyOptional(r)
|
|
if !ok {
|
|
panic("developer error: ExtractWorkspaceProxy middleware not provided")
|
|
}
|
|
return proxy
|
|
}
|
|
|
|
type ExtractWorkspaceProxyConfig struct {
|
|
DB database.Store
|
|
// Optional indicates whether the middleware should be optional. If true,
|
|
// any requests without the external proxy auth token header will be
|
|
// allowed to continue and no workspace proxy will be set on the request
|
|
// context.
|
|
Optional bool
|
|
}
|
|
|
|
// ExtractWorkspaceProxy extracts the external workspace proxy from the request
|
|
// using the external proxy auth token header.
|
|
func ExtractWorkspaceProxy(opts ExtractWorkspaceProxyConfig) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
token := r.Header.Get(WorkspaceProxyAuthTokenHeader)
|
|
if token == "" {
|
|
if opts.Optional {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Missing required external proxy token",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Split the token and lookup the corresponding workspace proxy.
|
|
parts := strings.Split(token, ":")
|
|
if len(parts) != 2 {
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
})
|
|
return
|
|
}
|
|
proxyID, err := uuid.Parse(parts[0])
|
|
if err != nil {
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
})
|
|
return
|
|
}
|
|
secret := parts[1]
|
|
if len(secret) != 64 {
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Get the proxy.
|
|
// nolint:gocritic // Get proxy by ID to check auth token
|
|
proxy, err := opts.DB.GetWorkspaceProxyByID(dbauthz.AsSystemRestricted(ctx), proxyID)
|
|
if xerrors.Is(err, sql.ErrNoRows) {
|
|
// Proxy IDs are public so we don't care about leaking them via
|
|
// timing attacks.
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
Detail: "Proxy not found.",
|
|
})
|
|
return
|
|
}
|
|
if err != nil {
|
|
httpapi.InternalServerError(w, err)
|
|
return
|
|
}
|
|
if proxy.Deleted {
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
Detail: "Proxy has been deleted.",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Do a subtle constant time comparison of the hash of the secret.
|
|
hashedSecret := sha256.Sum256([]byte(secret))
|
|
if subtle.ConstantTimeCompare(proxy.TokenHashedSecret, hashedSecret[:]) != 1 {
|
|
httpapi.Write(ctx, w, http.StatusUnauthorized, codersdk.Response{
|
|
Message: "Invalid external proxy token",
|
|
Detail: "Invalid proxy token secret.",
|
|
})
|
|
return
|
|
}
|
|
|
|
ctx = r.Context()
|
|
ctx = context.WithValue(ctx, workspaceProxyContextKey{}, proxy)
|
|
//nolint:gocritic // Workspace proxies have full permissions. The
|
|
// workspace proxy auth middleware is not mounted to every route, so
|
|
// they can still only access the routes that the middleware is
|
|
// mounted to.
|
|
ctx = dbauthz.AsSystemRestricted(ctx)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|
|
|
|
type workspaceProxyParamContextKey struct{}
|
|
|
|
// WorkspaceProxyParam returns the workspace proxy from the ExtractWorkspaceProxyParam handler.
|
|
func WorkspaceProxyParam(r *http.Request) database.WorkspaceProxy {
|
|
user, ok := r.Context().Value(workspaceProxyParamContextKey{}).(database.WorkspaceProxy)
|
|
if !ok {
|
|
panic("developer error: workspace proxy parameter middleware not provided")
|
|
}
|
|
return user
|
|
}
|
|
|
|
// ExtractWorkspaceProxyParam extracts a workspace proxy from an ID/name in the {workspaceproxy} URL
|
|
// parameter.
|
|
//
|
|
//nolint:revive
|
|
func ExtractWorkspaceProxyParam(db database.Store, deploymentID string, fetchPrimaryProxy func(ctx context.Context) (database.WorkspaceProxy, error)) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
proxyQuery := chi.URLParam(r, "workspaceproxy")
|
|
if proxyQuery == "" {
|
|
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
|
Message: "\"workspaceproxy\" must be provided.",
|
|
})
|
|
return
|
|
}
|
|
|
|
var proxy database.WorkspaceProxy
|
|
var dbErr error
|
|
if proxyQuery == "primary" || proxyQuery == deploymentID {
|
|
// Requesting primary proxy
|
|
proxy, dbErr = fetchPrimaryProxy(ctx)
|
|
} else if proxyID, err := uuid.Parse(proxyQuery); err == nil {
|
|
// Request proxy by id
|
|
proxy, dbErr = db.GetWorkspaceProxyByID(ctx, proxyID)
|
|
} else {
|
|
// Request proxy by name
|
|
proxy, dbErr = db.GetWorkspaceProxyByName(ctx, proxyQuery)
|
|
}
|
|
if httpapi.Is404Error(dbErr) {
|
|
httpapi.ResourceNotFound(rw)
|
|
return
|
|
}
|
|
if dbErr != nil {
|
|
httpapi.InternalServerError(rw, dbErr)
|
|
return
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, workspaceProxyParamContextKey{}, proxy)
|
|
next.ServeHTTP(rw, r.WithContext(ctx))
|
|
})
|
|
}
|
|
}
|