From 1b86254d71c69bbb53965a24bec1c8c8b0cee441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Fri, 29 Jan 2021 16:15:34 +0100 Subject: [PATCH] Add blogpost about custom integrations changes (#786) Co-authored-by: Franck Nijhof --- blog/2021-01-29-custom-integration-changes.md | 59 ++++++++++++++++++ static/img/profile/ludeeus.jpg | Bin 0 -> 23657 bytes 2 files changed, 59 insertions(+) create mode 100644 blog/2021-01-29-custom-integration-changes.md create mode 100644 static/img/profile/ludeeus.jpg diff --git a/blog/2021-01-29-custom-integration-changes.md b/blog/2021-01-29-custom-integration-changes.md new file mode 100644 index 00000000..4b1011b8 --- /dev/null +++ b/blog/2021-01-29-custom-integration-changes.md @@ -0,0 +1,59 @@ +--- +author: Joakim Sørensen +authorURL: https://github.com/ludeeus +authorImageURL: /img/profile/ludeeus.jpg +authorTwitter: ludeeus +title: Custom integration changes +--- + +Happy New Year everyone! 2021 is finally here 🎉 + +As you probably are aware, recently we were made aware of security issues in several popular custom integrations. You can read more about that here: + +- https://www.home-assistant.io/blog/2021/01/14/security-bulletin/ +- https://www.home-assistant.io/blog/2021/01/22/security-disclosure/ +- https://www.home-assistant.io/blog/2021/01/23/security-disclosure2/ + +In light of these incidents. Starting with the Home Assistant 2021.2.0 beta that was just released, we are changing two things that will affect custom integrations. + +## Deprecated utilities + +The `sanitize_filename` and `sanitize_path` helpers located in the `homeassistant.utils` package have been deprecated and are pending removal. This will happen with the release of Home Assistant 2021.4.0 scheduled for the first week of April this year. + +We have added `raise_if_invalid_filename` and `raise_if_invalid_path` as replacement. They are located in the same `homeassistant.utils` package. These new functions will raise a `ValueError` instead of relying on the developer comparing the output of the function to the input to see if it is different. This will prevent misuse. + +## Versions + +The second change is pretty cool! Versions! + +The [`manifest.json` file][manifest] now has added support for a `version` key. The version should be a string with a major, minor and patch version. For example, `"1.0.0"`. + +This version will help users communicate with you the version they had issues with. And if you ever find a security issue with your custom integration, Home Assistant will be able to block insecure versions from being used. + +**The `version` key will be required in a future version of Home Assistant.** + +## Hassfest updated + +`hassfest` is our internal tool that is used in Home Assistant to validate all integrations. In April we made this available as a GitHub Action to help you find issues in your custom integration. This action can be used in any custom integration hosted on GitHub. If you have not added that to your repository yet, now is the time! [Read more about that here][hassfest]. + +If you are using the `hassfest` GitHub action, you will now start to see warnings when it runs if you are missing the `version` key in your [`manifest.json` file][manifest]. This warning will become an error at a later point when the `version` key becomes fully required for custom integrations. + +## Serving files + +Making resources available to the user is a common use case for custom integrations, whether that is images, panels, or enhancements the user can use in Lovelace. The only way one should serve static files from a path is to use `hass.http.register_static_path`. Use this method and avoid using your own, as this can lead to serious bugs or security issues. + +```python +from pathlib import Path + +should_cache = False +files_path = Path(__file__).parent / "static" +hass.http.register_static_path("/api/my_integration/static", str(files_path), should_cache) +``` + +That's it for this update about custom integrations. Keep doing awesome stuff! Until next time 👋 + +[AwesomeVersion]: https://github.com/ludeeus/awesomeversion +[CalVer]: https://calver.org/ +[SemVer]: https://semver.org/ +[hassfest]: /blog/2020/04/16/hassfest +[manifest]: /docs/creating_integration_manifest diff --git a/static/img/profile/ludeeus.jpg b/static/img/profile/ludeeus.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f92a1d3fc502c317aaa91a1312d8ab18bf4c0625 GIT binary patch literal 23657 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