How is this CPT code in functions.php adding a hidden “products” category?

This is the normal behaviour of a custom post type. Any post type other than pages and posts has the post type name in the URL. So for this URL:

https://example.com/products/product-name/

“products” is the post type. Not the category. Similarly, when registering a post type, if has_archive is set to true, then all Products will be automatically viewable at:

https://example.com/products/

The rewrite and has_archive properties can be used to change which slug is used for each for these. For example, if you set:

'has_archive' => 'shop',
'rewrite'.    => [
    'slug'       => 'product',
    'with_front' => false,
],

Then the products archive URL will be:

https://example.com/shop/

And the individual products’ URL will be:

https://example.com/product/product-name/

In neither of these cases do you need a “product” or “shop” category.