Hakana: Taking Hack Significantly – Slack Engineering

TL; DR: We’re saying a brand new open supply kind checker for Hack, known as Hakana.


Slack launched in 2014, constructed with a number of love and likewise a number of PHP code.

We began migrating to a unique language known as Hack in 2016. Hack was created by Fb after they’d struggled to scale their operations with PHP. It provided extra type-safety than PHP, and it got here with an interpreter (known as HHVM) that would run PHP code sooner than PHP’s personal interpreter.

A lot has modified in PHP-land since we switched. PHP is quicker than it was once, and it has borrowed plenty of Hack options (corresponding to constructor property promotion). Quite a lot of the PHP neighborhood has additionally embraced kind checking — there at the moment are some nice third-party kind checkers to select from.

Sticking with Hack has given us entry to extra runtime velocity boosts, performance-enhancing language constructs like `async`, and a typechecker that’s extra strict by default than PHP typecheckers. However we’ve missed out on options supplied by PHP typecheckers, together with the power to customise kind inference guidelines to search out points particular to our codebase and automatic safety vulnerability detection.

Slack has lots of of builders writing Hack. We wish to give them the absolute best expertise, so final 12 months we began constructing a sort checker that would fill these gaps.

We’ve dubbed that static evaluation device Hakana, and it’s now available on GitHub!

Hakana relies on Psalm, an open-source PHP static evaluation device I created, and it’s written in Rust. Hakana re-uses a Hack parser that’s bundled with the Hack interpreter.

A bonus of writing it in Rust: with a little bit of prodding, Hakana can run nearly wherever. For instance, it runs in your web browser by way of WASM.

How we use Hakana

At Slack we run Hakana in CI to implement good code habits in a variety of areas. Right here’s an incomplete listing:

  • It prevents unused features and unused non-public strategies.
  • It prevents unused assignments inside closures.
  • It detects each inconceivable and redundant type-checks.
  • It warns us about potential SQL-injection assaults and cross-site scripting vulnerabilities (extra on this beneath).
  • It prevents misuse of inner Slack APIs (by way of plugin hooks).

We additionally use Hakana to automate type-aware API migrations (once more by way of plugin hooks) and to delete unused features in bulk. Due to Rust, these whole-codebase migrations are comparatively fast.

Safety

PHP makes it very easy to make a dynamically-rendered web site. PHP additionally makes it very easy to create an completely insecure dynamically-rendered web site.

Hack improves on this barely, by supporting a system for producing HTML output known as XHP. XHP is secure-by-default in opposition to cross-site scripting assaults, however it doesn’t cease you from leaking buyer information, and Hack doesn’t forestall you from capturing your self within the foot with a variety of different safety vulnerabilities.

For a number of causes (together with compliance obligations) Slack wanted a device that would uncover these vulnerabilities. Psalm, the sort checker that Hakana relies on, already does safety evaluation, so it was comparatively easy so as to add safety evaluation to Hakana as effectively.

Hakana isn’t the primary safety evaluation device for Hack — for years, Fb has been utilizing an inner, closed-source device called Zoncolan — however Hakana is the primary that everybody can use.

Hakana works in a lot the identical method as Zoncolan. It examines how information can move between totally different features in a codebase, and checks if attacker-controlled information can present up in locations it shouldn’t.

To this point, Hakana has discovered plenty of exploitable vulnerabilities in manufacturing code at Slack (that had been instantly fastened, and we checked our logs to make sure that the vulnerabilities had not truly ever been exploited).

Safety within the kind system

Hakana’s safety evaluation mode is a type of interprocedural evaluation — it seems on the method information flows between features. Hakana additionally helps detecting one kind of vulnerability (SQL injection) by way of intraprocedural evaluation, simply by inspecting sorts at perform boundaries.

To do that, Hakana borrows the idea of literal string sorts from Psalm. In Hack code we are able to outline a sort alias:

<<HakanaSpecialTypesLiteralString()>>
kind db_query_string = string;

Although the official Hack typechecker simply treats this as a string, Hakana treats it as a particular kind `literal-string`, a subtype of string that may solely be concatenated or interpolated with different literal-strings. Passing a string right into a perform that expects a literal-string causes Hakana to emit an error:

perform get_id_query(string $id): db_query_string 
    return "choose * from customers the place id = '$id'";
    // Error: The sort `string` is extra common
    // than the declared return kind `literal-string`

Extending Hakana

PHP static evaluation instruments are usually highly-customisable. Customisable static evaluation is de facto helpful for PHP, as a result of its interpreter permits plenty of tips (e.g. magic methods) that may confound one-size-fits-all static evaluation instruments.

Most of these tips don’t work in Hack code, so there’s far much less of a necessity for customisable static evaluation. Even so, we’ve discovered a number of worth in extending Hakana with plugins.

For instance, we use a customized plugin to inform Hakana {that a} methodology name on our inner End result object, $some_result->is_ok(), is equal to the extra verbose $some_result is ResultSuccess<_> typecheck.

We additionally use customized plugins to carry out type-aware migrations at velocity throughout your entire codebase.

Constructing a plugin system for Rust just isn’t easy — our customized model of Hakana wraps the open-source core as a library, utilizing its plugin hooks the place needed — however it’s an essential function for us.

Velocity

Hakana was tailored from Psalm, a sort checker written in PHP. Whereas PHP is quick for an interpreted language, it may’t compete with a compiled device. To research a codebase of Slack’s dimension — many thousands and thousands of strains of code — we wanted a device that’s as quick as attainable.

Hakana, written in Rust, runs about 5x sooner than the PHP-based device on which it’s modeled.

We haven’t spent a lot time tuning efficiency, however when analyzing the complete Slack codebase (about 5 million strains of code) efficiency is on par with the official Hack typechecker. That’s adequate for us, for now.

Why open-source Hakana?

Hack kind of seems like PHP however with extra sorts. In that respect it’s been in comparison with TypeScript. However in contrast to TypeScript, which compiles right down to JavaScript, Hack requires its customers to alter a number of their server infrastructure too.

Resulting from that top switching price, at present Hack is barely used at just a few firms. It’s attainable that no person else apart from Slack could have a purpose to make use of Hakana.

Even so, there are just a few the explanation why we predict it’s value open-sourcing:

  • 🔍 The broader programming language neighborhood could have helpful enter — particularly in the case of safety evaluation.
  • 🤝 Psalm, one other open-source device, was the idea for Hakana. By open-sourcing our personal device we’re returning the favor.
  • 🏢 Although it wouldn’t be simple, firms with extraordinarily giant PHP codebases may contemplate forking Hakana and altering it to investigate PHP code.

Conclusion

Slack is an indispensable device for thousands and thousands around the globe. Hack is now an integral a part of Slack, and so we’ve created a device that we hope will turn into indispensable to our Hack builders. We’re open-sourcing it today with the hope that others will discover it helpful and fascinating.