Tuesday, July 22, 2014

'Specified wildcard pattern is invalid' with Octopus Deploy and PSake

So we upgraded to Octopus Deploy v2, and all our deployments are now failing with this error:

22/07/2014 11:51:08 AM: An Error Occurred:
Info 11:51:08
Test-Path : Cannot retrieve the dynamic parameters for the cmdlet. The
Info 11:51:08
specified wildcard pattern is not valid:
Info 11:51:08
Octopus.Environment.MachinesInRole[myproject-sql-node]
At D:\Octopus\Applications\Test\ORDW.Staging.TPPS\7.0.310-trunk_1\Tools\Install
Info 11:51:08
\psake.psm1:357 char:17
Info 11:51:08
+ if (test-path "variable:\$key") {

Our install process is quite complex, so we use Psake to wrangle it. Integration between the two is relatively straightforward (in essence we just bind $octopusParameters straight onto psake's -properties), and I could see from the stack trace that the failure was actually happening within the PSake module itself. And given the error spat out the variable that caused the issue, I figured it was to do with the variable name.

Most of the variable names are the same as per Octopus Deploy v1, but we do now get some extra ones, in particular the 'Octopus.Environment.MachinesInRole[role]' one. But that's not so different from the type of variables we've always got from Octopus, eg: 'Octopus.Step[0].Name', so what's different?

Where psake is failing is where it pushes properties into variable scope for each of the tasks it executes as part of the 'build', and apparently it's choking because test-path doesn't like it. So I put together some tests to exercise test-path with different variable names, and find out when it squealed. This all works against the same code as runs in psake, ie:

test-path "variable:\$key"

$keyResult
aOk
a.bOk
a-bOk
b.aOk
b-aOk
a.b.cOk
a-b-cOk
c.b.aOk
c-b-aOk
a[a]Ok
a[a.b]Ok
a[a-b]Ok
a[b.a]Ok
a[b-a]Cannot retrieve the dynamic parameters for the cmdlet. 
The specified wildcard pattern is not valid: a[b-a]
a[a.b.c]Ok
a[a-b-c]Ok
a[c.b.a]Ok
a[c-b-b]Cannot retrieve the dynamic parameters for the cmdlet. 
The specified wildcard pattern is not valid: a[c-b-b]
a[b-b-a]Ok

I've highlighted the failure cases, but what's just as interesting is which cases pass. This gives a clue as to the underlying implementation, and why the failure happens.

To cut a long story short, it appears that any time you use square brackets in your variable name, PowerShell uses wildcard matching to parse the content within the brackets. If that content contains a hypen, then the letters before and after the first hyphen are used as a range for matching, and the range end is prior to the range start (ie: alphabetically earlier), you get an error.

Nasty.

It's hard to know who to blame here. Octopus makes those variables based on what roles you define in your environment, though I'd argue the square brackets is potentially a bad choice. PSake is probably partly culpable, though you'd be forgiven for thinking that what they were doing was just fine, and there's no obvious way of supressing the wildcard detection. Ultimately I think this is probably a PowerShell bug. Whichever way you look at it, the chances of me getting it fixed soon are fairly slight.

In this case I can just change all my Octopus role names to use dots not hypens, and I think I'll be out of the woods, but this could be a right royal mess to fix otherwise. I'd probably have to forcefully remove variables from scope just to keep PSake happy, which would be ugly.

Interestingly the documentation for Test-Path is a bit confused as to whether wildcard matching is or isn't allowed here - the description says they are, but Accept wildcard characters' claims otherwise:

PS C:\> help Test-Path -parameter:Path

-Path 
    Specifies a path to be tested. Wildcards are permitted. If the path includes spaces, enclose it in quotation marks. The parameter 
    name ("Path") is optional.
    
    Required?                    true
    Position?                    1
    Default value                
    Accept pipeline input?       True (ByValue, ByPropertyName)
    Accept wildcard characters?  false

Also interesting is that Set-Variable suffers from the same issue, for exactly the same cases (and wildcarding definitely doesn't make any sense there). Which means you can do this:
${a[b-a]} = 1
but not this
Set-Variable 'a[b-a]' 1
Go figure.


Update 23/7:
  • You can work around this by escaping the square brackets with backticks, eg Set-Variable 'a`[b-a`]'
  • I raised a Connect issue for this, because I think this is a bug
  • I've raised an issue with Psake on this, because I think they should go the escaping route to work around it.

Tuesday, April 15, 2014

It's time to bring Data Tainting to the CLR

Last week's Heartbleed bug once again exposes the shaky foundations of current software development processes. Decades-old issues such as inadvertent use of user-input values, and unintended access to memory (whether read or write) continue to be critical risks to the infrastructure on which our economies are increasingly reliant.

How do we deal with these risks? We implore developers to be more careful. This is clearly not working.

Risk-exposed industries (like resources) have mature models to categorize risk, and rate the effectiveness of mitigation strategies. Procedural fixes (telling people not to do something, putting up signs) rate at the bottom, are ranked lower than physical guards and such like. At the top are approaches that address the risk by doing something fundamentally less risky - engineering the risk away. As an industry, we could learn a thing or two here.

At times we have. The introduction of managed languages all but eliminated direct memory access bugs from those environments - no more buffer overruns, or read-after-free - but did little or nothing to address the issue of user input . And yet this is arguably the more important of the two - you still need untrustworthy data to turn direct memory access into a security hole. We just moved the problem elsewhere, and had a decade of SQLi and XSS attacks instead.

I think it's time to fix this. I think it's time we made the trustworthiness of data a first-class citizen in our modern languages. I think it's time to bring Data Tainting to the CLR.

Data Tainting is a language feature where all objects derived[1] from user input are flagged as 'tainted' unless explicitly cleared, a bit like that infamous 'downloaded from the internet' flag that block you running your downloads. Combined with other code paths asserting that their arguments are untainted, this can largely eliminate the problem of unsanitized user input being inadvertently trusted.

Taint Checking is not a new idea, it's just not very common outside of academia[2] (Perl and Ruby are the only extant languages I know of that support it, having strangely failed to take hold in JavaScript after Netscape introduced it last century). But it's exactly what we need if we are to stop making the same security mistakes, over and over again.

It has bugged me for over a decade that this never took off, but the last straw for me was questions like this on security overflow: Would Heartbleed have been prevented if OpenSSL was written in (blah) ... Why? Because the depressing answer is no. Whilst a managed implementation of TLS could not have a direct memory scraping vulnerability, the real bug here - that the output buffer sizing was based on what the client wrote in the input header - is not prevented. So the flaw could still be misused, perhaps allowing to DOS the SSL endpoint somehow.

Raw memory vulnerabilities are actually quite hard to exploit: you need to know a bit about the target memory model, and have a bit of luck too. Unsanitized input vulnerabilities, once you know about the flaw, are like shooting fish in a barrel: this input string here is directly passed to your database / shown to other users / used as your balance / written to the filesystem etc... The myriad ways we can find to exploit these holes should not be a testament not to our ingenuity, but highlight an elephant in the room: it's still too hard to write secure code. Can we do more to fall into the pit of success? I think so.

Implementing taint checking in the CLR will not be a trivial task by any means, so Microsoft are going to take a fair bit of persuading that matters enough to commit to. And that's where I need your help:
  • If any of this resonates with you, please vote for my user voice suggestion: bring Data Tainting to the CLR
  • If you think it sucks, comment on it (or this post) and tell me why
Imagine a world where Heartbleed could not happen. How do we get there?

Next time: what taint checking might look like on the CLR.

[1] Tainting spreads through operators, so combining tainted data with other data results in data with the taint bit set.
[2] Microsoft Research did a good review of the landscape here, if you can wade through the overly-theoretical bits: http://research.microsoft.com/pubs/176596/tr.pdf

Thursday, April 10, 2014

Could not load file or assembly ApprovalTests

If you get the following error when running ApprovalTests...
Could not load file or assembly 'ApprovalTests, Version=3.0.0.0, Culture=neutral, PublicKeyToken=11bd7d124fc62e0f' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
...make sure the assembly that your tests are in is not itself called ApprovalTests. As perhaps it might be if you were just demoing it to someone quickly. Doh!

Saturday, March 15, 2014

Another PowerShell Gotcha - Order of precidence and type inference

There was a fun moment at last week's Perth Dot Net User Group when the presenter (demonstrating Octopus Deploy's new scripting console), put in the following PowerShell:

> Write-Host [Environment]::MachineName

And got back (literally)

[Environment]::MachineName

...which wasn't what he expected at all. It's worth pausing to consider why this happens.

Remember of course that when passing strings as arguments in PowerShell, the quotes are optional - it would make a fairly poor shell replacement otherwise. So for example the following is completely valid:

> Write-Host Hello!

This is the reason[1] why variables in PowerShell have the dollar prefix - it makes their use in binding fairly unambiguous (just as the @ symbol in Razor achieves the same thing).

> $a = 'Moo'
> Write-Host $a

Moo

If you really wanted to write '$a' you'd have to enclose it in single quotes (as I just did) or escape the dollar symbol.

Anyway back to the original problem, you can see that PowerShell has two possible ways of interpreting

> Write-Host [Environment]::MachineName

...and since it doesn't start with a $, you get the 'bind to as an object' behavior, which - in this case - gives you a string (since it's clearly not a number).

What you really wanted was one of the following:

> Write-Host ([Environment]::MachineName)
> Write-Host $([Environment]::MachineName)

SOMECOMPUTERNAME

They both give the intended result, by forcing the expression within the brackets to be evaluated first (which on its own is unambiguous to the parser), and then passing the result of that as an argument to the bind for Write-Host.

This is really important trick to know, because will otherwise bite you again and again when you try and call a .Net method, and attempt to supply a parameter via an expression, for example:

$someClass.SomeMethod($a.length -1)
...when what you need to say is

$someClass.SomeMethod(($a.length -1))
Key take-home: When in doubt, add more brackets[2]

[1] presumably
[2] parenthesis

Saturday, May 25, 2013

Sql trivia: BINARY_CHECKSUM

You know how in SQL Books online the doco tells you to be wary of using CHECKSUM and BINARY_CHECKSUM functions because they will miss some updates. Here's a trivial example:

select 
 BINARY_CHECKSUM(A),
 BiggestInt,
 BINARY_CHECKSUM(BiggestInt)
from (
 select cast(null as int) as A,
 Power(cast(2 as bigint),31) -1 as BiggestInt
) x

Which returns 2147483647 in all 3 cases. So essentially BINARY_CHECKSUM is blind to the difference between a null and an int(max value). Which is fair enough... but does illustrate the point that even if you are only doing a checksum on a single nullable 4 byte field, you can't stuff it into 32 bits without getting at least one collision.

Thursday, March 14, 2013

Google Reader In Memoriam

So, Farewell Then Google Reader
Your feed
Has expired
Like Bloglines,
Which you killed
Off
I guess
Now
We'll just have to use
Something else
Instead
Google Reader was 7 1/2
(With apologies to E.J.Thribb)

Installing the Analysis Services Deployment Utility

The Analysis Services Deployment Utility is a utility that can be used to deploy Analysis Services build outputs (.asdatabase files) to a server, or to generate the XMLA for offline deployment.

I've often used this as part of an automated installation process to push releases out into an integration environment, but on this project I wanted to perform this installation as part of a nightly build. It failed - because the utility (and it's dependencies) weren't installed on the build server.

I wasn't entirely sure what I needed to get it installed (and I was attempting to install the minimum amount of stuff). It turns out this tool is distributed as part of Sql Management Studio, not the SSDT/BIDS projects (as I'd previously assumed). Not sure if the Basic or Complete option is required, because I picked 'complete' and that fixed it.

Also, for 2012 the path has changed, and the utility is now at:

C:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\ManagementStudio\Microsoft.AnalysisServices.Deployment.exe

Thursday, March 07, 2013

Installing BIDS project templates for SQL 2012

You can absolutely be forgiven for being confused about how to install the BIDS project templates for SQL 2012. They've moved to the new Sql Server Data Tools (SSDT), but Microsoft are themselves inconsistent about what SSDT is. To make matters worse, you've got Visual Studio 2010 and 2012 versions of each package, depending on what IDE you want to work in.

I'll attempt to clarify:

  • SSDT is only the updated SQL database project template, that replaces the Database Edition GDR / datadude stuff (and subsumes the SQL-CLR project type)
  • SSDT-BI is the other, ex-BIDS projects: SSIS, SSRS, SSAS
Unfortunately the SQL 2012 install media uses the term 'Sql Server Data Tools' to refer to both at the same time, and up-until-last-week the SSDT-BI project didn't exist outside of the SQL install media. Much confusion and delay. Hopefully the following guidance clears it up a bit:

If you only care about the SQL Server Database project


(eg: you are a C# developer, and your SQL database schema as a project in your solution)

Install the appropriate version of SSDT that matches the version of Visual Studio (2010 or 2012) you're using right now (or both if necessary):
Note these do not include the BIDS project templates (SSRS, SSIS, SSAS); they only include the new SQL Server Database project template.

If you are a BI developer, and want the lot

...in a Visual Studio 2010 Shell

Install the 'Sql Server Data Tools' component from the SQL 2012 install media. This gets you everything you need.
Optionally, also install the updated version of the SQL project template (only) by installing SSDT for Visual Studio 2010

...in a Visual Studio 2012 Shell

Install the standalone version of SSDT for Visual Studio 2012 (for the database project) and SSDT-BI for Visual Studio 2012 (for the SSRS, SSIS, SSAS templates)

...but don't know which shell to use

If you plan to create a single Visual Studio Solution (.sln) combining BIDS artifacts database projects and other project types (e.g. C# or VB projects), then that will determine your choice here. It's certainly easier working in just one IDE than having to have two open.

Otherwise just pick one. You might be swayed by some of the new VS 2012 features, then again you get the 2010 version already on the install media, so that option is less downloading. Given they shipped against one version, but now support the next as far as I can see they'll have to support both versions going forwards, at least for a couple of years.


Editors Note: This rewrite replaces the sarcastic rant I had here previously, which was quite cathartic, but not desperately helpful in navigating the landscape here.

Popular Posts