Remove deprecated credstash + keyring (#47033)

This commit is contained in:
Paulus Schoutsen 2021-02-25 00:48:19 -08:00 committed by GitHub
parent 72263abfa9
commit 633a7aeb22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 4 additions and 262 deletions

View file

@ -141,12 +141,7 @@ def run(script_args: List) -> int:
if sval is None:
print(" -", skey + ":", color("red", "not found"))
continue
print(
" -",
skey + ":",
sval,
color("cyan", "[from:", flatsecret.get(skey, "keyring") + "]"),
)
print(" -", skey + ":", sval)
return len(res["except"])

View file

@ -1,74 +0,0 @@
"""Script to get, put and delete secrets stored in credstash."""
import argparse
import getpass
from homeassistant.util.yaml import _SECRET_NAMESPACE
# mypy: allow-untyped-defs
REQUIREMENTS = ["credstash==1.15.0"]
def run(args):
"""Handle credstash script."""
parser = argparse.ArgumentParser(
description=(
"Modify Home Assistant secrets in credstash."
"Use the secrets in configuration files with: "
"!secret <name>"
)
)
parser.add_argument("--script", choices=["credstash"])
parser.add_argument(
"action",
choices=["get", "put", "del", "list"],
help="Get, put or delete a secret, or list all available secrets",
)
parser.add_argument("name", help="Name of the secret", nargs="?", default=None)
parser.add_argument(
"value", help="The value to save when putting a secret", nargs="?", default=None
)
# pylint: disable=import-error, no-member, import-outside-toplevel
import credstash
args = parser.parse_args(args)
table = _SECRET_NAMESPACE
try:
credstash.listSecrets(table=table)
except Exception: # pylint: disable=broad-except
credstash.createDdbTable(table=table)
if args.action == "list":
secrets = [i["name"] for i in credstash.listSecrets(table=table)]
deduped_secrets = sorted(set(secrets))
print("Saved secrets:")
for secret in deduped_secrets:
print(secret)
return 0
if args.name is None:
parser.print_help()
return 1
if args.action == "put":
if args.value:
the_secret = args.value
else:
the_secret = getpass.getpass(f"Please enter the secret for {args.name}: ")
current_version = credstash.getHighestVersion(args.name, table=table)
credstash.putSecret(
args.name, the_secret, version=int(current_version) + 1, table=table
)
print(f"Secret {args.name} put successfully")
elif args.action == "get":
the_secret = credstash.getSecret(args.name, table=table)
if the_secret is None:
print(f"Secret {args.name} not found")
else:
print(f"Secret {args.name}={the_secret}")
elif args.action == "del":
credstash.deleteSecrets(args.name, table=table)
print(f"Deleted secret {args.name}")

View file

@ -1,62 +0,0 @@
"""Script to get, set and delete secrets stored in the keyring."""
import argparse
import getpass
import os
from homeassistant.util.yaml import _SECRET_NAMESPACE
# mypy: allow-untyped-defs
REQUIREMENTS = ["keyring==21.2.0", "keyrings.alt==3.4.0"]
def run(args):
"""Handle keyring script."""
parser = argparse.ArgumentParser(
description=(
"Modify Home Assistant secrets in the default keyring. "
"Use the secrets in configuration files with: "
"!secret <name>"
)
)
parser.add_argument("--script", choices=["keyring"])
parser.add_argument(
"action",
choices=["get", "set", "del", "info"],
help="Get, set or delete a secret",
)
parser.add_argument("name", help="Name of the secret", nargs="?", default=None)
import keyring # pylint: disable=import-outside-toplevel
# pylint: disable=import-outside-toplevel
from keyring.util import platform_ as platform
args = parser.parse_args(args)
if args.action == "info":
keyr = keyring.get_keyring()
print("Keyring version {}\n".format(REQUIREMENTS[0].split("==")[1]))
print(f"Active keyring : {keyr.__module__}")
config_name = os.path.join(platform.config_root(), "keyringrc.cfg")
print(f"Config location : {config_name}")
print(f"Data location : {platform.data_root()}\n")
elif args.name is None:
parser.print_help()
return 1
if args.action == "set":
entered_secret = getpass.getpass(f"Please enter the secret for {args.name}: ")
keyring.set_password(_SECRET_NAMESPACE, args.name, entered_secret)
print(f"Secret {args.name} set successfully")
elif args.action == "get":
the_secret = keyring.get_password(_SECRET_NAMESPACE, args.name)
if the_secret is None:
print(f"Secret {args.name} not found")
else:
print(f"Secret {args.name}={the_secret}")
elif args.action == "del":
try:
keyring.delete_password(_SECRET_NAMESPACE, args.name)
print(f"Deleted secret {args.name}")
except keyring.errors.PasswordDeleteError:
print(f"Secret {args.name} not found")

View file

@ -1,5 +1,5 @@
"""YAML utility functions."""
from .const import _SECRET_NAMESPACE, SECRET_YAML
from .const import SECRET_YAML
from .dumper import dump, save_yaml
from .input import UndefinedSubstitution, extract_inputs, substitute
from .loader import clear_secret_cache, load_yaml, parse_yaml, secret_yaml
@ -7,7 +7,6 @@ from .objects import Input
__all__ = [
"SECRET_YAML",
"_SECRET_NAMESPACE",
"Input",
"dump",
"save_yaml",

View file

@ -1,4 +1,2 @@
"""Constants."""
SECRET_YAML = "secrets.yaml"
_SECRET_NAMESPACE = "homeassistant"

View file

@ -10,20 +10,9 @@ import yaml
from homeassistant.exceptions import HomeAssistantError
from .const import _SECRET_NAMESPACE, SECRET_YAML
from .const import SECRET_YAML
from .objects import Input, NodeListClass, NodeStrClass
try:
import keyring
except ImportError:
keyring = None
try:
import credstash
except ImportError:
credstash = None
# mypy: allow-untyped-calls, no-warn-return-any
JSON_TYPE = Union[List, Dict, str] # pylint: disable=invalid-name
@ -32,9 +21,6 @@ DICT_T = TypeVar("DICT_T", bound=Dict) # pylint: disable=invalid-name
_LOGGER = logging.getLogger(__name__)
__SECRET_CACHE: Dict[str, JSON_TYPE] = {}
CREDSTASH_WARN = False
KEYRING_WARN = False
def clear_secret_cache() -> None:
"""Clear the secret cache.
@ -299,43 +285,6 @@ def secret_yaml(loader: SafeLineLoader, node: yaml.nodes.Node) -> JSON_TYPE:
if not os.path.exists(secret_path) or len(secret_path) < 5:
break # Somehow we got past the .homeassistant config folder
if keyring:
# do some keyring stuff
pwd = keyring.get_password(_SECRET_NAMESPACE, node.value)
if pwd:
global KEYRING_WARN # pylint: disable=global-statement
if not KEYRING_WARN:
KEYRING_WARN = True
_LOGGER.warning(
"Keyring is deprecated and will be removed in March 2021."
)
_LOGGER.debug("Secret %s retrieved from keyring", node.value)
return pwd
global credstash # pylint: disable=invalid-name, global-statement
if credstash:
# pylint: disable=no-member
try:
pwd = credstash.getSecret(node.value, table=_SECRET_NAMESPACE)
if pwd:
global CREDSTASH_WARN # pylint: disable=global-statement
if not CREDSTASH_WARN:
CREDSTASH_WARN = True
_LOGGER.warning(
"Credstash is deprecated and will be removed in March 2021."
)
_LOGGER.debug("Secret %s retrieved from credstash", node.value)
return pwd
except credstash.ItemNotFound:
pass
except Exception: # pylint: disable=broad-except
# Catch if package installed and no config
credstash = None
raise HomeAssistantError(f"Secret {node.value} not defined")

View file

@ -448,9 +448,6 @@ construct==2.10.56
# homeassistant.components.coronavirus
coronavirus==1.1.1
# homeassistant.scripts.credstash
# credstash==1.15.0
# homeassistant.components.datadog
datadog==0.15.0
@ -844,12 +841,6 @@ kaiterra-async-client==0.0.2
# homeassistant.components.keba
keba-kecontact==1.1.0
# homeassistant.scripts.keyring
keyring==21.2.0
# homeassistant.scripts.keyring
keyrings.alt==3.4.0
# homeassistant.components.kiwi
kiwiki-client==0.1.1

View file

@ -239,9 +239,6 @@ construct==2.10.56
# homeassistant.components.coronavirus
coronavirus==1.1.1
# homeassistant.scripts.credstash
# credstash==1.15.0
# homeassistant.components.datadog
datadog==0.15.0
@ -455,12 +452,6 @@ influxdb==5.2.3
# homeassistant.components.verisure
jsonpath==0.82
# homeassistant.scripts.keyring
keyring==21.2.0
# homeassistant.scripts.keyring
keyrings.alt==3.4.0
# homeassistant.components.konnected
konnected==1.2.0

View file

@ -21,7 +21,6 @@ COMMENT_REQUIREMENTS = (
"blinkt",
"bluepy",
"bme680",
"credstash",
"decora",
"decora_wifi",
"envirophat",
@ -47,7 +46,7 @@ COMMENT_REQUIREMENTS = (
"VL53L1X2",
)
IGNORE_PIN = ("colorlog>2.1,<3", "keyring>=9.3,<10.0", "urllib3")
IGNORE_PIN = ("colorlog>2.1,<3", "urllib3")
URL_PIN = (
"https://developers.home-assistant.io/docs/"

View file

@ -1,6 +1,5 @@
"""Test Home Assistant yaml loader."""
import io
import logging
import os
import unittest
from unittest.mock import patch
@ -15,14 +14,6 @@ from homeassistant.util.yaml import loader as yaml_loader
from tests.common import get_test_config_dir, patch_yaml_files
@pytest.fixture(autouse=True)
def mock_credstash():
"""Mock credstash so it doesn't connect to the internet."""
with patch.object(yaml_loader, "credstash") as mock_credstash:
mock_credstash.getSecret.return_value = None
yield mock_credstash
def test_simple_list():
"""Test simple list."""
conf = "config:\n - simple\n - list"
@ -294,20 +285,6 @@ def load_yaml(fname, string):
return load_yaml_config_file(fname)
class FakeKeyring:
"""Fake a keyring class."""
def __init__(self, secrets_dict):
"""Store keyring dictionary."""
self._secrets = secrets_dict
# pylint: disable=protected-access
def get_password(self, domain, name):
"""Retrieve password."""
assert domain == yaml._SECRET_NAMESPACE
return self._secrets.get(name)
class TestSecrets(unittest.TestCase):
"""Test the secrets parameter in the yaml utility."""
@ -395,27 +372,6 @@ class TestSecrets(unittest.TestCase):
"http:\n api_password: !secret test",
)
def test_secrets_keyring(self):
"""Test keyring fallback & get_password."""
yaml_loader.keyring = None # Ensure its not there
yaml_str = "http:\n api_password: !secret http_pw_keyring"
with pytest.raises(HomeAssistantError):
load_yaml(self._yaml_path, yaml_str)
yaml_loader.keyring = FakeKeyring({"http_pw_keyring": "yeah"})
_yaml = load_yaml(self._yaml_path, yaml_str)
assert {"http": {"api_password": "yeah"}} == _yaml
@patch.object(yaml_loader, "credstash")
def test_secrets_credstash(self, mock_credstash):
"""Test credstash fallback & get_password."""
mock_credstash.getSecret.return_value = "yeah"
yaml_str = "http:\n api_password: !secret http_pw_credstash"
_yaml = load_yaml(self._yaml_path, yaml_str)
log = logging.getLogger()
log.error(_yaml["http"])
assert {"api_password": "yeah"} == _yaml["http"]
def test_secrets_logger_removed(self):
"""Ensure logger: debug was removed."""
with pytest.raises(HomeAssistantError):