Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351). > [!WARNING] > **DO NOT MERGE** until [DOCS-349](https://linear.app/codercom/issue/DOCS-349) ([coder.com#877](https://github.com/coder/coder.com/pull/877)) has shipped to production and baked for at least one Vercel cycle. > > Without DOCS-349, the relative links in this PR resolve to broken docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the rewriter to classify these as GitHub blob/tree URLs with the page's resolved ref. ## TL;DR Converts 121 absolute `https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39 docs markdown files to relative paths. After this lands AND DOCS-349 deploys, every one of these links will follow the displayed docs version (mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on `/@main/`) instead of always pointing to `main`. ## Why Today a reader on `/docs/@v2.30.0/install/docker` follows a `compose.yaml` link and arrives at `main`'s `compose.yaml`, which doesn't necessarily match what the docs page describes. Helm values, Terraform templates, and source-code references in particular drift across versions. The fix is to let the coder.com rewriter substitute the page's resolved ref into the URL; that only works on relative links. ## Example payoff (post-DOCS-349) | URL | Today (absolute, always `main`) | After (relative + rewriter) | |---|---|---| | `/docs/install/docker` | `https://github.com/coder/coder/blob/main/compose.yaml` | `https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's mainline) | | `/docs/@v2.30.0/install/docker` | same as above | `https://github.com/coder/coder/blob/v2.30.0/compose.yaml` | | `/docs/@main/install/docker` | same as above | `https://github.com/coder/coder/blob/main/compose.yaml` | ## Scope - **121 conversions** across **39 files**. - Verb breakdown: `tree/main` (directories) and `blob/main` (files), both flipped to relative paths. - Line anchors (`#L23-L24`) and query strings preserved verbatim. - Conversion is mechanical: relative path computed from the doc file's directory to the target via `os.path.relpath`. Any path starting at the same directory or below gets a `./` prefix; otherwise `../` chains. ## Rebased on main The branch was rebased onto `main` after the DOCS-350 hotfix ([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`, which then needed the same `main` -> relative conversion this PR is doing for the other 121 links. The conflict was resolved by reapplying the mechanical conversion to `backend.md` after taking the hotfix's content. Net result: those 3 links land here as relative, same as everything else. New HEAD `3f501cb622`. ## Inline fix folded in: dead `nix` link - `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix` The original absolute URL `https://github.com/coder/coder/tree/main/nix` already returned 404 today. Repointed to `flake.nix` (modern Nix entrypoint, what the prose "Nix environment" semantically refers to). Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since the `check-docs` Linkspector job surfaced it during rebase; cheaper to fix inline than in a separate single-line PR. ## Out of scope (filed separately) - [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead `docs-backend-contrib-guide` branch refs in `backend.md` ([#26339](https://github.com/coder/coder/pull/26339), merged). - [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned `(blob|tree)/<sha>` links pending intent review. - [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server analog (4 absolute `(blob|tree)/main` links in `coder/code-server`). - [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of this PR). ## Not triggering `/coder-agents-review` Docs-only edit; per `AGENTS.md` the bot review is reserved for product/CI changes. ## Pre-mortem | Concern | Mitigation | |---|---| | Merging before DOCS-349 deploys regresses ~120 currently-working links into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker in Linear. | | Relative path computed incorrectly (off-by-one `..`) | Verified all 114 newly-relative non-md/non-image paths resolve to existing files in the repo (only exception is the pre-existing dead `nix` link above). | | Line anchors stripped during conversion | Preserved by the substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and `speed-up-templates.md`. | | Future code reorgs change file locations | Relative links will start pointing to nothing. Same failure mode as absolute links pointing to renamed files; can be caught with a future link-checker job. | ## Validation ``` $ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l 0 $ git diff --stat origin/main | tail -1 39 files changed, 118 insertions(+), 118 deletions(-) ``` 114 newly-relative paths verified to resolve to existing repo files (Python `os.path.exists` check on each computed target). <details> <summary>Decision log + planning context</summary> **Why relative over `(blob|tree)/{{currentDocsVersion}}/...` templating**: relative paths require zero markdown-system support and zero upstream churn beyond this one PR. Templating would require a preprocessor on `coder.com` side AND a convention upstream authors have to remember; relative paths just work in a plain editor and `github.com`'s own renderer too. **Why `./` prefix on same-directory targets**: makes the conversion grep-able later (`grep -E '\((\.\./|\./)'`). **Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful to the linked file's content, not to the URL form; keeping it as-is preserves authorial intent. If the file later changes such that the line range drifts, that's a different problem the SHA-pin audit ([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface. </details> --- *Generated by Coder Agents on @nickvigilante's behalf.* ## Drive-by external link fix folded in `docs/about/contributing/CONTRIBUTING.md:296` cited `https://reflectoring.io/meaningful-commit-messages/` which is returning HTTP 503 (the host appears to be down site-wide right now). `check-docs` Linkspector flagged it after the rebase. Replaced with `https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this commit will..." article, confirmed 200), which is the original source of the rule the prose recites anyway.
6.0 KiB
JFrog Artifactory Integration
Use Coder and JFrog Artifactory together to secure your development environments without disturbing your developers' existing workflows.
This guide will demonstrate how to use JFrog Artifactory as a package registry within a workspace.
Requirements
- A JFrog Artifactory instance
- 1:1 mapping of users in Coder to users in Artifactory by email address or username
- Repositories configured in Artifactory for each package manager you want to use
Provisioner Authentication
The most straight-forward way to authenticate your template with Artifactory is by using our official Coder modules. We publish two type of modules that automate the JFrog Artifactory and Coder integration.
JFrog-OAuth
This module is usable by JFrog self-hosted (on-premises) Artifactory as it requires configuring a custom integration. This integration benefits from Coder's external-auth feature allows each user to authenticate with Artifactory using an OAuth flow and issues user-scoped tokens to each user.
To set this up, follow these steps:
-
Add the following to your Helm chart
values.yamlfor JFrog Artifactory. ReplaceCODER_URLwith your JFrog Artifactory base URL:artifactory: enabled: true frontend: extraEnvironmentVariables: - name: JF_FRONTEND_FEATURETOGGLER_ACCESSINTEGRATION value: "true" access: accessConfig: integrations-enabled: true integration-templates: - id: "1" name: "CODER" redirect-uri: "https://CODER_URL/external-auth/jfrog/callback" scope: "applied-permissions/user" -
Create a new Application Integration by going to
https://JFROG_URL/ui/admin/configuration/integrations/app-integrations/newand select the Application Type as the integration you created in step 1 orCustom Integrationif you are using SaaS instance i.e. example.jfrog.io. -
Add a new external authentication to Coder by setting these environment variables in a manner consistent with your Coder deployment. Replace
JFROG_URLwith your JFrog Artifactory base URL:# JFrog Artifactory External Auth CODER_EXTERNAL_AUTH_1_ID="jfrog" CODER_EXTERNAL_AUTH_1_TYPE="jfrog" CODER_EXTERNAL_AUTH_1_CLIENT_ID="YYYYYYYYYYYYYYY" CODER_EXTERNAL_AUTH_1_CLIENT_SECRET="XXXXXXXXXXXXXXXXXXX" CODER_EXTERNAL_AUTH_1_DISPLAY_NAME="JFrog Artifactory" CODER_EXTERNAL_AUTH_1_DISPLAY_ICON="/icon/jfrog.svg" CODER_EXTERNAL_AUTH_1_AUTH_URL="https://JFROG_URL/ui/authorization" CODER_EXTERNAL_AUTH_1_SCOPES="applied-permissions/user" -
Create or edit a Coder template and use the JFrog-OAuth module to configure the integration:
module "jfrog" { count = data.coder_workspace.me.start_count source = "registry.coder.com/modules/jfrog-oauth/coder" version = "1.0.19" agent_id = coder_agent.example.id jfrog_url = "https://example.jfrog.io" username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" package_managers = { npm = ["npm", "@scoped:npm-scoped"] go = ["go", "another-go-repo"] pypi = ["pypi", "extra-index-pypi"] docker = ["example-docker-staging.jfrog.io", "example-docker-production.jfrog.io"] } }
JFrog-Token
This module makes use of the Artifactory terraform provider and an admin-scoped token to create user-scoped tokens for each user by matching their Coder email or username with Artifactory. This can be used for both SaaS and self-hosted (on-premises) Artifactory instances.
To set this up, follow these steps:
-
Get a JFrog access token from your Artifactory instance. The token must be an admin token with scope
applied-permissions/admin. -
Create or edit a Coder template and use the JFrog-Token module to configure the integration and pass the admin token. It is recommended to store the token in a sensitive Terraform variable to prevent it from being displayed in plain text in the terraform state:
variable "artifactory_access_token" { type = string sensitive = true } module "jfrog" { source = "registry.coder.com/modules/jfrog-token/coder" version = "1.0.30" agent_id = coder_agent.example.id jfrog_url = "https://XXXX.jfrog.io" artifactory_access_token = var.artifactory_access_token package_managers = { npm = ["npm", "@scoped:npm-scoped"] go = ["go", "another-go-repo"] pypi = ["pypi", "extra-index-pypi"] docker = ["example-docker-staging.jfrog.io", "example-docker-production.jfrog.io"] } }
Note
The admin-level access token is used to provision user tokens and is never exposed to developers or stored in workspaces.
If you don't want to use the official modules, you can read through the example template, which uses Docker as the underlying compute. The same concepts apply to all compute types.
Air-Gapped Deployments
See the air-gapped deployments section for instructions on how to use Coder modules in an offline environment with Artifactory.
Next Steps
-
See the full example Docker template.
-
To serve extensions from your own VS Code Marketplace, check out code-marketplace.