Migrate Redirect Map builds the 301 redirects a Drupal 7 to Drupal 10/11 migration needs and reports, before launch, which legacy URLs would return 404. It reads the migrate map tables of the node, taxonomy term, user and media migrations (both d7_node_complete:bundle IDs and the upgrade_d7_* IDs written by the Migrate Drupal UI), the legacy url_alias table and the legacy redirect table, resolves each legacy path to the alias the migrated entity actually has on the new site, and classifies it as redirect / identical / already exists / unresolved. A dry run writes the full map to CSV; creation runs through the Batch API (or drush migrate-redirect-map:build) with loop protection and no duplicates. Drupal 7 translation sets (tnid) are followed, and aliases in a language the new site does not have become language-neutral redirects.

How it differs from existing solutions

  • The Redirect module's d7_path_redirect migration only copies redirects that already existed on the Drupal 7 site. It does nothing for aliases that changed because entity IDs were renumbered or because Pathauto patterns changed.
  • Core's d7_url_alias migration copies the old aliases, which keeps old URLs working only when nothing else changed; it cannot tell you which paths now resolve nowhere.
  • This module compares legacy paths with the new site's real aliases after the migrations and alias generation have run, creates a redirect only where the URL actually changed, and gives a list of unresolved paths (views, custom callbacks, file paths) so they can be mapped by hand before launch.

Manual reviews

Project link

https://www.drupal.org/project/migrate_redirect_map

Comments

shaker-gspikes created an issue. See original summary.

shaker-gspikes’s picture

Issue summary: View changes
Issue tags: +PAreview: review bonus
vishal.kadam’s picture

Issue summary: View changes
shaker-gspikes’s picture

Issue summary: View changes
avpaderno’s picture

Thank you for applying!

Before giving links helpful to understand how the review process works, what to expect from a review, and what to do to avoid a review takes more time than needed, I would like to thank all the reviewers for the work they do.
These applications are volunters-driven, which also means it is not possible to predict when an application will be marked fixed and the applicant will get the permission to opt projects into security advisory policy. While we aim to make an application as quick as possible, it is also important for us that more people review the project used for an application. In this way, we make sure applications do not miss some important points that should be instead reported.
Applications are not meant to be complete debugging sessions that eliminate every existing bug, though. I apologize if sometimes applications seem to go into too-detailed reviews.

Please read Review process for security advisory coverage: What to expect for more details and Security advisory coverage application checklist to understand what reviewers look for. Tips for ensuring a smooth review gives some hints for a smoother review.

The important notes are the following.

  • If you have not done it yet, you should enable GitLab CI for the project and fix the PHP_CodeSniffer errors/warnings it reports.
  • For the time this application is open, only your commits are allowed.
  • The purpose of this application is giving you a new drupal.org role that allows you to opt projects into security advisory coverage, either projects you already created, or projects you will create. The project status will not be changed by this application; once this application is closed, you will be able to change the project status from Not covered to Opt into security advisory coverage. This is possible only 14 days after the project is created.

    Keep in mind that once the project is opted into security advisory coverage, only Security Team members may change coverage.
  • Only the person who created the application will get the permission to opt projects into security advisory coverage. No other person will get the same permission from the same application; that applies also to co-maintainers/maintainers of the project used for the application.
  • We only accept an application per user. If you change your mind about the project to use for this application, or it is necessary to use a different project for the application, please update the issue summary with the link to the correct project and the issue title with the project name and the branch to review.

To the reviewers

Please read How to review security advisory coverage applications, Application workflow, What to cover in an application review, and Tools to use for reviews.

The important notes are the following.

  • It is preferable to wait for a project moderator before posting the first comment on newly created applications. Project moderators will do some preliminary checks that are necessary before any change on the project files is suggested.
  • For the tools to use for reviewing a project, see Tools to use for reviews.
  • It may be best to have the applicant fix things before further reviews and avoid doing a review when another review is pending.

For new reviewers, I would also suggest to first read In which way the issue queue for coverage applications is different from other project queues.

vishal.kadam’s picture

Status: Needs review » Needs work

1. FILE: README.md

The README file is missing the required section - Configuration.

2. FILE: migrate_redirect_map.module

For a new module that aims to be compatible with Drupal 10 and Drupal 11, I would rather implement hooks as class methods as described in Support for object oriented hook implementations using autowired services.

avpaderno’s picture

Issue tags: -PAreview: review bonus
shaker-gspikes’s picture

Status: Needs work » Needs review
Issue tags: +PAreview: review bonus

Thank you both. The two points from #6 are addressed in 1.0.x at 6456b082; the pipeline on that commit is green.

1. README.md now has a Configuration section between Installation and Usage. It says that nothing is stored and describes the three per-run options (legacy database key, migrations, dry run) and the permission the report page needs.

2. hook_help() is now a method of the new src/Hook/MigrateRedirectMapHooks.php class (#[Hook('help')], string translation injected through autowiring, service declared in migrate_redirect_map.services.yml). Because the module supports Drupal 10.3, migrate_redirect_map.module keeps a procedural migrate_redirect_map_help() marked #[LegacyHook] that delegates to the same service, so 10.3 to 11.0 still find the hook and 11.1+ does not run it twice. Checked on Drupal 10.6: the help page and the report page text render once and the route link resolves; the unit tests pass.

Setting back to Needs review. The second round of reviews is already linked in the issue summary (#3607891 comment #16802885, #3609892 comment #16802888, #3573362 comment #16802890), so I am adding the review bonus tag back; please remove it if that round does not qualify.

avpaderno’s picture

Issue summary: View changes
Issue tags: -PAreview: review bonus

Reviews needs to be for different project applications; reviewing the same application twice does not count as second round of reviews.

shaker-gspikes’s picture

Issue summary: View changes
Issue tags: +PAreview: review bonus

I added three more manual reviews to the issue summary. They are of applications I had not reviewed before, since a second round has to cover different applications:

Adding the PAreview: review bonus tag again.

anil_bhutia’s picture

Thank you for the fixes in 6456b08. I reviewed the 1.0.x branch manually; phpcs is clean and the pipeline for that commit is green.

Previously raised points

  • hook_help() is now a #[Hook('help')] method on MigrateRedirectMapHooks, registered by class name with autowire: true, and the procedural migrate_redirect_map_help() has #[LegacyHook] and delegates to the service. That is the pattern from https://www.drupal.org/node/3442349. (The class: line in services.yml is redundant when the service ID is the class name.)
  • The README now has a Configuration section.

Checked and fine: all queries use the query builder (no concatenated table names or values); the only route is a form, so no CSRF issue; report cells are plain strings and #markup/help text use placeholders; the builder, form and Drush command use DI.

src/RedirectMapBuilder.php

  1. Lines 164-174 and 222-247: before creating a redirect, please check that the source path is not live on the new site. Step 2 creates node/12 → node/345 without checking whether node 12 exists on the new site, and a legacy alias may now belong to a different entity or match a real route (for example a D7 alias such as user/login). Redirect's RedirectRequestSubscriber runs before routing and applies processInbound() first, so such a redirect would also capture every alias of the new node 12. Could these be reported with a separate "conflict" status and skipped?
  2. Lines 268-275: createRedirect() saves without $redirect->validate(). Redirect has a RedirectUniqueHash constraint and a unique key on hash, while findMatchingRedirect() only finds enabled redirects, so an existing disabled redirect (or two legacy languages that both become und) ends in an integrity exception. Please validate and report violations; the legacy status_code (line 185) should also be checked against redirect_status_code_options().
  3. Lines 186-195: the elseif on line 192 is always true, so STATUS_EXTERNAL is never reported and external legacy targets become ordinary redirects. If that is intended, the dead branch and constant can go; I would still suggest reporting external targets separately (ideally opt-in). Also, LegacyPathMapper::isExternal() says it follows UrlHelper::isExternal(), but it accepts javascript:/data: and does not treat //host as external. Please use UrlHelper::isExternal() plus UrlHelper::isValid($url, TRUE) and allow only http/https.
  4. Lines 95-116: the map table is queried directly (sourceid1/destid1) through the default connection. Iterating the id map via MigrateIdMapInterface (currentSource()/currentDestination()) avoids relying on Sql plugin internals, and filtering migration IDs before createInstances() would avoid instantiating every migration.
  5. Lines 178-179: D7 source_options/redirect_options are not read, so query-specific legacy redirects collapse and target query strings are lost.
  6. Lines 309-328: CSV cells starting with =, +, -, @ (or tab/CR) are not neutralised, and legacy aliases were typed by editors. Please prefix such cells, for example with '.
  7. The reason strings are shown in the UI but are not translatable.

src/Form/MigrateRedirectMapForm.php

  1. Line 79: the whole map is built synchronously in submitForm() (one alias and one redirect lookup per path); only creation is batched. For the 50,000-alias case in the README, consider building the map in a batch too.
  2. Lines 87-94: the CSV is written to temporary:// on every submit, never removed, and not downloadable from the UI. Returning it as an attachment from the submit handler would be more useful.
  3. Lines 82 and 92 show raw exception messages to the user; please log them and show a generic message.

migrate_redirect_map.routing.yml

  • The page lets the user pick any database key from settings.php and bulk-create redirects, but it is guarded by administer redirects. A dedicated permission with restrict access: true seems more appropriate.

src/Drush/Commands/MigrateRedirectMapCommands.php

  • Without --dry-run the command writes straight away, while the UI defaults to a dry run. Please consider $this->io()->confirm().

Tests

  • Only LegacyPathMapper is unit tested. Since the resolver is the core of the module, please add a kernel test (for example extending MigrateTestBase, which provides the migrate source connection) that creates minimal url_alias/redirect tables and id map rows and asserts each status, including the collision, duplicate and external-target cases above.

Setting to Needs work mainly for points 1-3 on RedirectMapBuilder; the rest are recommendations.

anil_bhutia’s picture

Status: Needs review » Needs work