Repository navigation
Psalm 7
#13062
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Psalm 7
Announcing the release of Psalm 7!
Featuring a simply enormous number of new features and bug fixes, such as:
php://inputand uploaded file names, flows through closures, generators, traits and by-reference parameters, and ready-made stubs for Guzzle, PSR-7, Monolog, MongoDB and more.io,time,write-props...), with purity templates for classes, closures and automatically inferred annotations;@template TError of Throwable = RuntimeException) for classes, functions and methods:Result<int>just works, and libraries can add templates without breaking their users.dev-master.Psalm 7 runs on 64-bit PHP 8.2 to 8.6. Upgrading is simple for most projects: see Upgrading below.
Security analysis: faster, always on, in a single run
Taints are now stored as a bitmask, and the taint graph is resolved over compact summaries of each function. This makes security analysis up to 10x faster.
Combined analysis (#11384) runs type checking, security analysis and dead code detection together in one run, so taint analysis is now on by default (#11399).
Taint issues are reported with a
SECURITYseverity, and with a rank in SARIF reports (#12068, #11383). The results no longer change between runs or with the thread count (#11946, #11952, #11953).Deeper taint tracking
TaintedNosql(MongoDB sinks),TaintedLlmPrompt(prompt injection), andTaintedUrlComponent/TaintedUrlPath(query and path injection). curl options andCURLFileare reported by what they do: SSRF, header injection, file access, sleep or callables. Every taint type is now documented (Add nosql taint type and mark MongoDB sinks #11944, [7.x] AddTaintedLlmPromptissue type for prompt injection detection #11746, Add new taint kinds for query and path injection #12097, Report curl options and CURLFile by what they do: SSRF, header injection, files, sleep and callables #12099, Document every taint type #12468).php://input,STDIN, the client-sent entries of$_SERVERand$_FILES,getopt(),$argv, DNS answers, exception messages, and the files, paths and URLs builtins read (Taint php://input & STDIN sources, and propagate taint through closures #11945, Taint the entries of $_SERVER and $_FILES the client sends #12086, Treat the command-line options getopt() returns as a taint source of user input #12246, Treat $argv, bound with global or read through $GLOBALS too, as a taint source of user input #12245, Taint DNS answers, and the paths and URLs more builtins read, write and connect to #12135, Taint the messages of exceptions, and the exceptions a catch block gets #12139).foreachby reference, global and static variables, trait method bodies, promoted constructor properties,__toString(), inherited methods and their overrides, exceptions, and builtin functions and objects (Taint what closures are called with and return through variables and callable parameters #12147, Taint what generators yield and what iterating over objects gives #12096, Taint what functions and builtins leave in by-reference parameters #12095, Taint the array a foreach by reference writes into #12121, Track taints through global variables, with a node per global shared by $GLOBALS and global #12243, Track taints through the static variables of function-likes across their calls #12255, Track taint through the bodies of trait methods, keyed by the class using the trait #12272, Make the taints of promoted constructor parameters flow into their properties #12091, Convert an object to a string with the taints of what its __toString returns #12127, Taint the result of a call on an interface or base class with the returns of its overrides #12262, Make taints flow through the builtins that return data from their arguments #12084, Taint what builtin objects are given and give back, described by a dictionary #12102).inthas nohtmltaint). Array keys are tracked much more precisely. Inferred-pure functions are specialized per call, and@psalm-cli-onlymarks code whose output isn't an HTML response (Remove the taints a value's type cannot hold, at returns, sources and assignments #12079, Drop the taints a narrowed type can't carry, also where it can carry others #12348, Assign under each literal the key of an array assignment can be #12150, Taint analysis: know more array keys (literal unions, array_map(), convergences, key starts of lists) and stop at keys overwritten in specialized calls #12375, Specialize taints of calls to inferred-pure functions #12048, Add @psalm-cli-only: what command-line code prints isn't an HTML sink #12459).loadLibraryStubs, on by default) (Load the stubs Psalm ships for libraries when the scanned code uses one of their classes #12460–Add a library stub for the emails webklex/php-imap receives as taint sources #12467, Load a library stub when the scanned code declares one of its functions #12481–Add a library stub for the NoSQL sinks of mongodb/mongodb's Collection and Database #12484).@psalm-taint-sink ($mode is 0 ? null : 'html') $content(Support conditional taint sinks: @psalm-taint-sink ($mode is 0 ? null : 'html') $content #12458);@psalm-taint-sink sql $params[*](Taint analysis: sinks on the values of an array parameter only ($param[*]) #12171);@psalm-taint-source input return['key'](Support @psalm-taint-source input return['key']: a source under a key of the return only #12455);~(html|has_quotes)(Accept taint complements ~(kind|kind): every taint, custom ones included, but the kinds listed #12300);@psalm-flowthrough callables (($compute()) -> return), the receiver (($this) -> return),$thisproperties, and keyed stores (($value) -> Store::$data[$key]) (Support @psalm-flow ($compute()) -> return: what a callable parameter returns flows to the return #12299, Let @psalm-flow ($this) -> return carry the taints of the object a method is called on #12302, Let @psalm-flow set and return properties of $this by name #12456, Follow values through keyed stores: @psalm-flow ($value) -> Store::$data[$key] and back to return #12312, Store what callables return in keyed stores: @psalm-flow ($compute()) -> Store::$data[$key] #12327);@psalm-taint-property-bag(Read and write the properties of a class through the array property @psalm-taint-property-bag names #12486);psalm.xml(Declare custom taints in psalm.xml, optionally added to the input aliases #12330).Codebase::getTaintNode(),getTaintPropertyNode(),addTaintPath(),getReceiverTaintPath(), and the taint nodes of a call's return value, arguments and receiver (Let plugins add taint paths: Codebase::getTaintNode(), getTaintPropertyNode(), addTaintPath() #12454, Add Codebase::getReceiverTaintPath(), the path along which a method of a builtin class returns what its object holds #12414, Let plugins get the taint nodes of the return, arguments and object of a call, and assign properties #12489, Let plugins give an expression the taint nodes of a list, without their internal ids #12535).A new purity model: capabilities
@psalm-pure,@psalm-mutation-freeand@psalm-external-mutation-freeare replaced by capabilities, modelled on Hack's contexts and capabilities. A function-like declares exactly which side effects it may have:read-props,write-this-props,write-props,read-globals,write-globals,write-refs,ioandtime, withpureandimpureat the two ends (#11984):<psalm suggestPurityAnnotations="true">to getMissingPureAnnotationandMissingImmutableAnnotation(and their abstract and interface variants), and run--alter --issues=MissingPureAnnotation,MissingImmutableAnnotationto add the annotations. The--altercommand works without the attribute. The suggestions are opt-in.clone,__toString(),__invoke(),ArrayAccess, destructors,new $classand parameter defaults are now checked too.@psalm-purecan be used on classes, and plugins can declare the capabilities of the methods they handle.The new Purity Model article explains the model in full.
Purity templates
Many functions are only as pure as what they are given:
array_map()is pure when its callback is. Purity templates are template parameters whose values are capability sets instead of types, like Hack's[ctx $f]contexts. A function can now be both pure and higher-order, and each call costs only what its arguments do (#11984).With
Closure[_], a function takes its purity from the closure it is given:On a class, a purity template lets each subclass decide what its methods may do:
Traversable,Iterator,IteratorAggregateandGeneratorhave a purity template, for what iterating over them does.iterablehas one too. A generator with a purity annotation binds it to what its body does:Closure[io](int): void,Handler[pure],Iterator[pure]<int, string>,Box[io]<int>. Named templates are declared with@psalm-purity-template Pand used with@psalm-purity-from-template P.@psalm-purity-template write-this-props <= C(write-this-props) <= write-this-props|write-props|io. A method may use the lower bound unconditionally. Subclasses must stay within the bounds, and get the default when they don't bind the template.Closure[P]parameter or a conditional@returnon__construct. For example,new ArrayObject([...])is anArrayObject[pure], so a pure function may fill anArrayObjectit created (Charge the class purity templates constructors depend on at new #12116, Let a constructor's @return give the type of the object it constructs #12179, Charge ArrayObject and ArrayIterator mutators write-props only when their storage is an object #12190).--alteraddsClosure[_]to the closure parameters a function calls (Purity templates: omitted purity arguments, instanceof narrowing, inference of templated calls #12077, Add the_purity to the closure parameters a function-like calls with --alter #12019).array_map,usort,preg_replace_callback,iterator_to_array,CallbackFilterIterator,Fiberand more (Declare what the methods of the SPL classes do #12122).See Purity templates in the Purity Model article.
Graph-based dead code detection
Unused code is now found on a graph of references (#11939). Code is used only if it can be reached from an entry point, so classes and methods referenced only by other unused code, cycles included, are reported. Exceptions that are created but never thrown are reported too (#12487):
--find-unused-psalm-suppressnow also checks suppressions on classes and onTainted*issues.Type system
Template defaults: a template can declare a default type,
@template T = Defaultor@template T of Bound = Default, on classes, interfaces, traits, functions and methods. Psalm uses it when the type argument is left out: in@extends/@implements/@use, in a generic type with only its first arguments (Result<int>), innew, and in calls that don't infer the template. Libraries can add a template without breaking everyFoo<A>their users wrote, and those users no longer getMissingTemplateParam. See Template defaults.New types and syntax:
decimal-int-stringandnon-decimal-int-string, global constant wildcards, conditional types on types that depend on a template,is notin conditional types, and exact intersections of scalar and conditional types.Constructor
@returntypes.New
IntMaskComparisonissue for int-masks compared by value.PHP 8.5 and 8.6
Psalm runs on PHP 8.6 and has a PHP 8.6 call map.
The PHP 8.5 pipe operator and PHP 8.6 partial function application are fully typed: Psalm infers the type of every pipeline stage and the signature of every partially applied closure, so a stage that doesn't fit the previous one is reported :
Plugins
^0.4): Composer will then only install the plugin with a Psalm release whose plugin API it was written for.psalm/plugin-phpunit,plugin-mockery,plugin-symfony,plugin-laravelandplugin-sabre-event, and enables each one, plus the webmozart/assert plugin, when yourcomposer.jsonuses the matching library (loadLibraryPlugins, on by default) (Require the psalm/* plugins and enable them, and the webmozart/assert plugin, for the libraries a project uses #12568, Require psalm/plugin-laravel 4.x, the line built for Psalm 7.x #12570, Enable the Laravel plugin when composer.json requires orchestra/testbench #12571).ERROR_LEVEL([7.x] Allow plugin issues to specify custom documentation URLs #11735, [7.x] RespectERROR_LEVELfor plugin-defined issues #11736).CLI and configuration
--init-cigenerates a GitHub Actions workflow that runs the official Docker image, pinned to the Psalm version in yourcomposer.lock. The docs now cover the Psalm GitHub Action and the Psalm Security Scan action, which sends security analysis results to GitHub code scanning.ghcr.io/psalm/psalm.compactoutput format is renamedtable, and a new, truly compactcompactformat is added.<unsuppressibleIssues>makes the issues it lists impossible to suppress.Upgrading
For most projects, upgrading is as simple as updating the Composer dependency:
Everything else is in the upgrade guide.
Most projects will notice:
runTaintAnalysis="false"to opt out.<psalm suggestPurityAnnotations="true">, newMissingPureAnnotation/MissingImmutableAnnotationissues appear for code that can be annotated. Fix them with--alter --issues=MissingPureAnnotation,MissingImmutableAnnotation. The annotations Psalm adds improve both security analysis and type inference:$a->get() !== null ? $a->get() : ''is astring. Without@psalm-immutable, the second call is still?string.Thanks
Thanks to everyone who contributed to Psalm 7, and to everyone who tested the betas and release candidates and reported issues!
Full Changelog: 6.20.3...7.0.0
This discussion was created from the release Psalm 7.
All reactions