From b7eab64efb23f4415922a363d020dcf705c022d1 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Mon, 28 Feb 2022 15:14:58 +0100
Subject: [PATCH] feat(config): deprecate non-default npm presets (#14444)

Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
---
 docs/development/shareable-configs.md         | 97 -------------------
 docs/usage/config-presets.md                  | 26 +----
 docs/usage/configuration-options.md           |  4 +-
 .../usage/getting-started/private-packages.md |  3 +-
 lib/config/presets/npm/index.ts               |  6 ++
 5 files changed, 14 insertions(+), 122 deletions(-)
 delete mode 100644 docs/development/shareable-configs.md

diff --git a/docs/development/shareable-configs.md b/docs/development/shareable-configs.md
deleted file mode 100644
index 3f665feac1..0000000000
--- a/docs/development/shareable-configs.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Preset configs
-
-Renovate uses the term "presets" to refer to shareable config snippets, similar to ESLint.
-Unlike ESLint though:
-
-- Presets may be as small as a list of package names, or as large as a full config
-- Shared config files can contain many presets
-
-Presets can be defined using either npm packages, or with GitHub/GitLab repositories.
-Only the JSON format is supported.
-Bitbucket-hosted presets are yet to be implemented.
-
-## Preset config URIs
-
-In human-understandable form, the rules are:
-
-- A full preset URI consists of package name, preset name, and preset parameters, such as `package:preset(param)`
-- If a package scope is specified and no package exists, then the package name is assumed to be `renovate-config`, e.g. `@rarkins:webapp` is expanded to `@rarkins/renovate-config:webapp`
-- If a non-scoped package is specified then it is assumed to have the prefix `renovate-config-`. e.g. `rarkins:webapp` is expanded to `renovate-config-rarkins:webapp`
-- If a package name is specified and has no preset name, then `default` is assumed, e.g. `@rarkins` expands in full to `@rarkins/renovate-config:default` and `rarkins` expands in full to `renovate-config-rarkins:default`
-- There is a special "default" namespace where no package name is necessary. e.g. `:webapp` (not the leading `:`) expands to `renovate-config-default:webapp`
-
-## Supported config syntax
-
-### Scoped
-
-| name                                               | example use                                 | preset    | npm package resolves as      | parameters |
-| -------------------------------------------------- | ------------------------------------------- | --------- | ---------------------------- | ---------- |
-| scoped                                             | `@somescope`                                | `default` | `@somescope/renovate-config` |            |
-| scoped with package name                           | `@somescope/somepackagename`                | `default` | `@somescope/somepackagename` |            |
-| scoped with preset name                            | `@somescope:webapp`                         | `webapp`  | `@somescope/renovate-config` |            |
-| scoped with param                                  | `@somescope(eslint)`                        | `default` | `@somescope/renovate-config` | `eslint`   |
-| scoped with preset name and param                  | `@somescope:webapp(eslint)`                 | `webapp`  | `@somescope/renovate-config` | `eslint`   |
-| scoped with package name and preset name           | `@somescope/somepackagename:webapp`         | `webapp`  | `@somescope/somepackagename` |            |
-| scoped with package name and preset name and param | `@somescope/somepackagename:webapp(eslint)` | `webapp`  | `@somescope/somepackagename` | `eslint`   |
-
-### Non-scoped
-
-If you use a non-scoped config, you must use a preset name!
-
-| name                                        | example use                                       | preset    | npm package resolves as           | parameters |
-| ------------------------------------------- | ------------------------------------------------- | --------- | --------------------------------- | ---------- |
-| non-scoped short with preset name           | `somepackagename:default`                         | `default` | `renovate-config-somepackagename` |            |
-| non-scoped short with preset name and param | `somepackagename:default(eslint)`                 | `default` | `renovate-config-somepackagename` | `eslint`   |
-| non-scoped full with preset name            | `renovate-config-somepackagename:default`         | `default` | `renovate-config-somepackagename` |            |
-| non-scoped full with preset name and param  | `renovate-config-somepackagename:default(eslint)` | `default` | `renovate-config-somepackagename` | `eslint`   |
-
-### Git based
-
-In general, GitHub, GitLab or Gitea-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs.
-An additional benefit of using source code hosting is that the same token/authentication can be reused by Renovate in case you want to make your config private.
-
-You can set a Git tag (like a SemVer) to use a specific release of your shared config.
-
-#### GitHub
-
-| name                                        | example use                      | preset    | resolves as                  | filename        | Git tag        |
-| ------------------------------------------- | -------------------------------- | --------- | ---------------------------- | --------------- | -------------- |
-| GitHub default                              | `github>abc/foo`                 | `default` | `https://github.com/abc/foo` | `default.json`  | Default branch |
-| GitHub with preset name                     | `github>abc/foo:xyz`             | `xyz`     | `https://github.com/abc/foo` | `xyz.json`      | Default branch |
-| GitHub default with a tag                   | `github>abc/foo#1.5.4`           | `default` | `https://github.com/abc/foo` | `default.json`  | `1.5.4`        |
-| GitHub with preset name with a tag          | `github>abc/foo:xyz#1.5.4`       | `xyz`     | `https://github.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-| GitHub with preset name and path with a tag | `github>abc/foo//path/xyz#1.5.4` | `xyz`     | `https://github.com/abc/foo` | `path/xyz.json` | `1.5.4`        |
-| GitHub with subpreset name and tag          | `github>abc/foo:xyz/sub#1.5.4`   | `sub`     | `https://github.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-
-#### GitLab
-
-| name                                        | example use                      | preset    | resolves as                  | filename        | Git tag        |
-| ------------------------------------------- | -------------------------------- | --------- | ---------------------------- | --------------- | -------------- |
-| GitLab default                              | `gitlab>abc/foo`                 | `default` | `https://gitlab.com/abc/foo` | `default.json`  | Default branch |
-| GitLab with preset name                     | `gitlab>abc/foo:xyz`             | `xyz`     | `https://gitlab.com/abc/foo` | `xyz.json`      | Default branch |
-| GitLab default with a tag                   | `gitlab>abc/foo#1.5.4`           | `default` | `https://gitlab.com/abc/foo` | `default.json`  | `1.5.4`        |
-| GitLab with preset name with a tag          | `gitlab>abc/foo:xyz#1.5.4`       | `xyz`     | `https://gitlab.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-| GitLab with preset name and path with a tag | `gitlab>abc/foo//path/xyz#1.5.4` | `xyz`     | `https://gitlab.com/abc/foo` | `path/xyz.json` | `1.5.4`        |
-| GitLab with subpreset name and tag          | `gitlab>abc/foo:xyz/sub#1.5.4`   | `sub`     | `https://gitlab.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-
-#### Gitea
-
-| name                                       | example use                     | preset    | resolves as                 | filename        | Git tag        |
-| ------------------------------------------ | ------------------------------- | --------- | --------------------------- | --------------- | -------------- |
-| Gitea default                              | `gitea>abc/foo`                 | `default` | `https://gitea.com/abc/foo` | `default.json`  | Default branch |
-| Gitea with preset name                     | `gitea>abc/foo:xyz`             | `xyz`     | `https://gitea.com/abc/foo` | `xyz.json`      | Default branch |
-| Gitea default with a tag                   | `gitea>abc/foo#1.5.4`           | `default` | `https://gitea.com/abc/foo` | `default.json`  | `1.5.4`        |
-| Gitea with preset name with a tag          | `gitea>abc/foo:xyz#1.5.4`       | `xyz`     | `https://gitea.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-| Gitea with preset name and path with a tag | `gitea>abc/foo//path/xyz#1.5.4` | `xyz`     | `https://gitea.com/abc/foo` | `path/xyz.json` | `1.5.4`        |
-| Gitea with subpreset name and tag          | `gitea>abc/foo:xyz/sub#1.5.4`   | `sub`     | `https://gitea.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-
-#### Self-hosted Git
-
-| name                                       | example use                     | preset    | resolves as                          | filename        | Git tag        |
-| ------------------------------------------ | ------------------------------- | --------- | ------------------------------------ | --------------- | -------------- |
-| Local default                              | `local>abc/foo`                 | `default` | `https://github.company.com/abc/foo` | `default.json`  | Default branch |
-| Local with preset path                     | `local>abc/foo:path/xyz`        | `default` | `https://github.company.com/abc/foo` | `path/xyz.json` | Default branch |
-| Local default with a tag                   | `local>abc/foo#1.5.4`           | `default` | `https://github.company.com/abc/foo` | `default.json`  | `1.5.4`        |
-| Local with preset name with a tag          | `local>abc/foo:xyz#1.5.4`       | `default` | `https://github.company.com/abc/foo` | `xyz.json`      | `1.5.4`        |
-| Local with preset name and path with a tag | `local>abc/foo//path/xyz#1.5.4` | `default` | `https://github.company.com/abc/foo` | `path/xyz.json` | `1.5.4`        |
-| Local with subpreset name and tag          | `local>abc/foo:xyz/sub#1.5.4`   | `sub`     | `https://github.company.com/abc/foo` | `xyz.json`      | `1.5.4`        |
diff --git a/docs/usage/config-presets.md b/docs/usage/config-presets.md
index c6539005c3..b7afb02a3e 100644
--- a/docs/usage/config-presets.md
+++ b/docs/usage/config-presets.md
@@ -41,9 +41,11 @@ In order to achieve these goals, preset configs allow for a very modular approac
 
 ## Preset Hosting
 
-In general, GitHub, GitLab or Gitea-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs.
+Presets should be hosted in repositories, which usually means the same platform host as Renovate is running against.
 
-An additional benefit of using source code hosting is that the same token/authentication can be reused by Renovate in case you want to make your config private.
+<!-- prettier-ignore -->
+!!! warning
+    npm-based presets are deprecated and support will be removed in a future major release.
 
 You can set a Git tag (like a SemVer) to use a specific release of your shared config.
 
@@ -168,9 +170,6 @@ Or if you think your preset would be valuable for others, please contribute a PR
 
 ## GitHub-hosted Presets
 
-It is also possible to host your preset config using just a regular GitHub repository and without needing to publish it to npmjs.
-In such cases Renovate will simply look for a `default.json` file in the default branch, e.g. `main`.
-
 To host your preset config on GitHub:
 
 - Create a new repository. Normally you'd call it `renovate-config` but it can be named anything
@@ -188,9 +187,6 @@ You do not need to add it as a devDependency or add any other files to the prese
 
 ## GitLab-hosted Presets
 
-It is also possible to host your preset config using just a regular GitLab repository and without needing to publish it to npmjs.
-In such cases Renovate will simply look for a `default.json` file in the default branch.
-
 For a private GitLab repository Renovate requires at least _Reporter_ level access.
 
 To host your preset config on GitLab:
@@ -201,9 +197,6 @@ To host your preset config on GitLab:
 
 ## Gitea-hosted Presets
 
-It is also possible to host your preset config using just a regular Gitea repository and without needing to publish it to npmjs.
-In such cases Renovate will simply look for a `default.json` file in the default branch.
-
 To host your preset config on Gitea:
 
 - Create a new repository on Gitea. Normally you'd call it `renovate-config` but you can use any name you want
@@ -217,17 +210,6 @@ This is especially helpful in self-hosted scenarios where public presets cannot
 Local presets are specified either by leaving out any prefix, e.g. `owner/name`, or explicitly by adding a `local>` prefix, e.g. `local>owner/name`.
 Renovate will determine the current platform and look up the preset from there.
 
-## Presets and Private Modules
-
-Using your own preset config along with private npm modules can present a chicken and egg problem.
-You want to configure the encrypted token just once, which means in the preset.
-But you also probably want the preset to be private too, so how can the other repos reference it?
-
-The answer is to host your preset using GitHub or GitLab - not npmjs - and make sure you have added the preset's repo to Renovate too.
-GitHub will then allow Renovate to access the preset repo whenever it is processing any other repos within the same account/org.
-
-For a private GitLab repository Renovate requires at least _Reporter_ level access.
-
 ## Contributing to presets
 
 Have you configured a rule that you think others might benefit from?
diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 59ef0fc81c..032860d856 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -575,8 +575,8 @@ Configure this option if you prefer a different title for the Dependency Dashboa
 
 ## description
 
-The description field is used by config presets to describe what they do.
-They are then collated as part of the onboarding description.
+The description field can be used inside any configuration object to add a human-readable description of the object's config purpose.
+Descriptions fields embedded within presets are also collated as part of the onboarding description.
 
 ## digest
 
diff --git a/docs/usage/getting-started/private-packages.md b/docs/usage/getting-started/private-packages.md
index 11804223a5..5ae2e03783 100644
--- a/docs/usage/getting-started/private-packages.md
+++ b/docs/usage/getting-started/private-packages.md
@@ -32,7 +32,8 @@ There are four times in Renovate's behavior when it may need credentials:
 Renovate supports config presets, including those which are private.
 
 Although npm presets were the first type supported, they are now deprecated and it is recommend that all users migrate to git-hosted "local" presets instead.
-However if you do still use them, private modules should work if you configure the `npmrc` file including token credentials in your bot global config.
+However if you do still use them, private modules should work if you configure `hostRules` (recommended) or `npmrc` including token credentials in your bot global config.
+It is strongly recommended not to use private modules on a private registry and a warning will be logged if that is found.
 Credentials stored on disk (e.g. in `~/.npmrc`) are no longer supported.
 
 The recommended way of using local presets is to configure then using "local" presets, e.g. `"extends": ["local>myorg/renovate-config"]`, and ensure that the platform token has access to that repo.
diff --git a/lib/config/presets/npm/index.ts b/lib/config/presets/npm/index.ts
index ab79ac34b8..d5d7fb1ff1 100644
--- a/lib/config/presets/npm/index.ts
+++ b/lib/config/presets/npm/index.ts
@@ -20,6 +20,12 @@ export async function getPreset({
   let dep;
   try {
     const { packageUrl } = resolvePackage(packageName);
+    // istanbul ignore if
+    if (!packageUrl.startsWith('https://registry.npmjs.org/')) {
+      logger.warn(
+        'npm presets from non-default registries are now deprecated. Please migrate to repository-based presets instead.'
+      );
+    }
     const body = (await http.getJson<NpmResponse>(packageUrl)).body;
     dep = body.versions[body['dist-tags'].latest];
   } catch (err) {
-- 
GitLab