Repository: pypa/pipenv

Issue:
Import Private Github Repo via Environment Variables 
You can use `pip` to pull a private Github repo using environment variables. 

```
# requirements.txt
git+https://${AUTH_USER}:${AUTH_PASSWORD}@github.com/user/myproject.git@1.2.3#egg=myproject
```

Then run

```
> pip install -r requirements.txt
```

Is there a way to do this with Pipenv? I tried using the environment variable method described [here](https://docs.pipenv.org/advanced/#injecting-credentials-into-pipfiles-via-environment-variables), but it looks like it's not the right approach.

```
Could not find a version that matches myproject (from -r /var/folders/6r/719kpmn511l0ghtx4v1rbxdm0000gn/T/pipenv-5xvfp5mw-requirements/pipenv-wm4ivcah-constraints.txt (line 11))
No versions found
Were https://pypi.python.org/simple or git+https://${AUTH_USER}:${AUTH_PASSWORD}@github.com/user/myproject.git#egg=myproject reachable?
```

<details><summary>$ pipenv --support</summary>

Pipenv version: `'2018.7.1'`

Pipenv location: `'/usr/local/lib/python2.7/site-packages/pipenv'`

Python location: `'/usr/local/opt/python@2/bin/python2.7'`

Other Python installations in `PATH`:

  - `2.7`: `/usr/local/bin/python2.7`
  - `2.7`: `/usr/local/bin/python2.7`
  - `2.7`: `/usr/bin/python2.7`
  - `3.6`: `/usr/local/bin/python3.6m`
  - `3.6`: `/usr/local/bin/python3.6`

  - `2.7.14`: `/usr/local/bin/python`
  - `2.7.10`: `/usr/bin/python`
  - `2.7.14`: `/usr/local/bin/python2`
  - `3.6.5`: `/usr/local/bin/python3`

PEP 508 Information:

```
{'implementation_name': 'cpython',
 'implementation_version': '0',
 'os_name': 'posix',
 'platform_machine': 'x86_64',
 'platform_python_implementation': 'CPython',
 'platform_release': '17.6.0',
 'platform_system': 'Darwin',
 'platform_version': 'Darwin Kernel Version 17.6.0: Tue May  8 15:22:16 PDT 2018; root:xnu-4570.61.1~1/RELEASE_X86_64',
 'python_full_version': '2.7.14',
 'python_version': '2.7',
 'sys_platform': 'darwin'}
```

System environment variables:

  - `AUTH_USER`
  - `AUTH_PASSWORD`

Pipenv–specific environment variables:


Debug–specific environment variables:

  - `PATH`: `/Users/juansc/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/opt/X11/bin:/Users/juansc/git/go/bin`
  - `SHELL`: `/bin/zsh`
  - `LANG`: `en_US.UTF-8`
  - `PWD`: `/Users/juansc/git/project/`


---------------------------

Contents of `Pipfile` ('/Users/juansc/git/project/Pipfile'):

```toml
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[[source]]
url = "git+https://${AUTH_USER}:${AUTH_PASSWORD}@github.com/user/myproject.git#egg=myproject"
verify_ssl = true
name = "myproject-name"

[packages]
myproject = {'ref'='1.2.3', index="myproject-name"}

[requires]
python_version = "3.6"

```

Contents of `Pipfile.lock` ('/Users/juansc/git/project/Pipfile.lock'):

```json
{
    "_meta": {
        "hash": {
            "sha256": "c4290d9b83dd0d70dc2972be0caa2eb452670ce057ca3b973290f5b618020783"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.python.org/simple",
                "verify_ssl": true
            },
            {
                "name": "myproject-name",
                "url": "git+https://${AUTH_USER}:${AUTH_PASSWORD}@github.com/user/myproject.git#egg=myproject",
                "verify_ssl": true
            }
        ]
    },
    "default": {
    }
}

```
</details>



Discussion:

Resolving patch:
diff --git a/pipenv/core.py b/pipenv/core.py
--- a/pipenv/core.py
+++ b/pipenv/core.py
@@ -1,6 +1,7 @@
 import json as simplejson
 import logging
 import os
+import re
 import shutil
 import sys
 import tempfile
@@ -23,6 +24,7 @@
     install_req_from_parsed_requirement,
 )
 from pipenv.patched.pip._internal.req.req_file import parse_requirements
+from pipenv.patched.pip._internal.utils.misc import split_auth_from_netloc
 from pipenv.project import Project
 from pipenv.utils.constants import MYPY_RUNNING
 from pipenv.utils.dependencies import (
@@ -198,9 +200,19 @@ def import_requirements(project, r=None, dev=False):
     for package in reqs:
         if package.name not in BAD_PACKAGES:
             if package.link is not None:
-                package_string = (
-                    f"-e {package.link}" if package.editable else str(package.link)
-                )
+                if package.editable:
+                    package_string = f"-e {package.link}"
+                else:
+                    netloc, (user, pw) = split_auth_from_netloc(package.link.netloc)
+                    safe = True
+                    if user and not re.match(r"\${[\W\w]+}", user):
+                        safe = False
+                    if pw and not re.match(r"\${[\W\w]+}", pw):
+                        safe = False
+                    if safe:
+                        package_string = str(package.link._url)
+                    else:
+                        package_string = str(package.link)
                 project.add_package_to_pipfile(package_string, dev=dev)
             else:
                 project.add_package_to_pipfile(str(package.req), dev=dev)


Test patch:
diff --git a/tests/integration/test_import_requirements.py b/tests/integration/test_import_requirements.py
new file mode 100644
--- /dev/null
+++ b/tests/integration/test_import_requirements.py
@@ -0,0 +1,67 @@
+import os
+from pathlib import Path
+import tempfile
+
+import pytest
+
+from pipenv.core import import_requirements
+from pipenv.project import Project
+
+
+@pytest.mark.cli
+@pytest.mark.deploy
+@pytest.mark.system
+def test_auth_with_pw_redacted(PipenvInstance):
+    with PipenvInstance(chdir=True) as p:
+        p.pipenv("run shell")
+        project = Project()
+        requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False)
+        requirements_file.write("""git+https://${AUTH_USER}:mypw1@github.com/user/myproject.git#egg=myproject""")
+        requirements_file.close()
+        import_requirements(project, r=requirements_file.name)
+        os.unlink(requirements_file.name)
+        assert p.pipfile["packages"]["myproject"] == {'git': 'https://${AUTH_USER}:****@github.com/user/myproject.git'}
+
+
+@pytest.mark.cli
+@pytest.mark.deploy
+@pytest.mark.system
+def test_auth_with_username_redacted(PipenvInstance):
+    with PipenvInstance(chdir=True) as p:
+        p.pipenv("run shell")
+        project = Project()
+        requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False)
+        requirements_file.write("""git+https://username@github.com/user/myproject.git#egg=myproject""")
+        requirements_file.close()
+        import_requirements(project, r=requirements_file.name)
+        os.unlink(requirements_file.name)
+        assert p.pipfile["packages"]["myproject"] == {'git': 'https://****@github.com/user/myproject.git'}
+
+
+@pytest.mark.cli
+@pytest.mark.deploy
+@pytest.mark.system
+def test_auth_with_pw_are_variables_passed_to_pipfile(PipenvInstance):
+    with PipenvInstance(chdir=True) as p:
+        p.pipenv("run shell")
+        project = Project()
+        requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False)
+        requirements_file.write("""git+https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git#egg=myproject""")
+        requirements_file.close()
+        import_requirements(project, r=requirements_file.name)
+        os.unlink(requirements_file.name)
+        assert p.pipfile["packages"]["myproject"] == {'git': 'https://${AUTH_USER}:${AUTH_PW}@github.com/user/myproject.git'}
+
+@pytest.mark.cli
+@pytest.mark.deploy
+@pytest.mark.system
+def test_auth_with_only_username_variable_passed_to_pipfile(PipenvInstance):
+    with PipenvInstance(chdir=True) as p:
+        p.pipenv("run shell")
+        project = Project()
+        requirements_file = tempfile.NamedTemporaryFile(mode="w+", delete=False)
+        requirements_file.write("""git+https://${AUTH_USER}@github.com/user/myproject.git#egg=myproject""")
+        requirements_file.close()
+        import_requirements(project, r=requirements_file.name)
+        os.unlink(requirements_file.name)
+        assert p.pipfile["packages"]["myproject"] == {'git': 'https://${AUTH_USER}@github.com/user/myproject.git'}
diff --git a/tests/integration/test_install_twists.py b/tests/integration/test_install_twists.py
--- a/tests/integration/test_install_twists.py
+++ b/tests/integration/test_install_twists.py
@@ -205,6 +205,7 @@ def test_normalize_name_install(PipenvInstance):
 @pytest.mark.files
 @pytest.mark.local
 @pytest.mark.resolver
+@pytest.mark.skip  # extracting this package where it does mamy be causing the pip_to_deps failures
 def test_local_package(PipenvInstance, pip_src_dir, testsroot):
     """This test ensures that local packages (directories with a setup.py)
     installed in editable mode have their dependencies resolved as well"""
@@ -234,13 +235,15 @@ def test_local_package(PipenvInstance, pip_src_dir, testsroot):
 def test_local_zipfiles(PipenvInstance, testsroot):
     file_name = "requests-2.19.1.tar.gz"
     # Not sure where travis/appveyor run tests from
-    source_path = os.path.abspath(os.path.join(testsroot, "test_artifacts", file_name))
+    source_path = os.path.join(testsroot, "test_artifacts", file_name)
 
     with PipenvInstance(chdir=True) as p:
         # This tests for a bug when installing a zipfile in the current dir
-        shutil.copy(source_path, os.path.join(p.path, file_name))
+        destination = os.path.join(p.path, file_name)
+        shutil.copy(source_path, destination)
 
         c = p.pipenv(f"install {file_name}")
+        os.unlink(destination)
         assert c.returncode == 0
         key = [k for k in p.pipfile["packages"].keys()][0]
         dep = p.pipfile["packages"][key]
@@ -268,6 +271,7 @@ def test_relative_paths(PipenvInstance, testsroot):
         shutil.copy(source_path, os.path.join(artifact_path, file_name))
         # Test installing a relative path in a subdirectory
         c = p.pipenv(f"install {artifact_dir}/{file_name}")
+        os.unlink(f"{artifact_dir}/{file_name}")
         assert c.returncode == 0
         key = next(k for k in p.pipfile["packages"].keys())
         dep = p.pipfile["packages"][key]